You are on page 1of 125

SUGAR DEVELOPER GUIDE

VERSION 5.1
Sugar Developer Guide

Version 5.1, 2008

Copyright © 2008 SugarCRM Inc.

www.sugarcrm.com

This document is subject to change without notice.

License
This work is licensed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0
License (“License”). To view a copy of this license, visit http://www.creativecommons.org/licenses/by-
nc-nd/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California,
94105, USA.

Disclaimer
Your Warranty, Limitations of liability and Indemnity are expressly stated in the License. Please refer to
the License for the specific language governing these rights and limitations

Trademarks
All SugarCRM logos in this document are registered trademarks of SugarCRM Inc. See the SugarCRM
trademark policies at http://www.sugarcrm.com/crm/open-source/trademark-information.html for more
information on how SugarCRM trademarks can be used.
Contents

Preface .......................................................................................................................................................... 5 
About this Guide ....................................................................................................................................... 5 
Audience ................................................................................................................................................... 5 
Overview ................................................................................................................................................... 5 
Core Features ........................................................................................................................................ 6 
What’s New in 5.1 ................................................................................................................................ 7 
Related Documentation ............................................................................................................................. 7 
Chapter 1 SugarCRM Overview ................................................................................................................... 9 
Platform Overview .................................................................................................................................... 9 
Application Framework Overview............................................................................................................ 9 
Directory Structure.............................................................................................................................. 11 
Key Concepts ...................................................................................................................................... 11 
Entry Points......................................................................................................................................... 12 
Module Framework Overview ................................................................................................................ 13 
User Interface Framework Overview ...................................................................................................... 16 
Extension Framework Overview ............................................................................................................ 16 
Sugar Dashlets Overview ........................................................................................................................ 17 
Web Services Overview .......................................................................................................................... 17 
Chapter 2 Application Framework .............................................................................................................. 18 
Entry Points............................................................................................................................................. 18 
File Caching ............................................................................................................................................ 18 
Sugar Dashlets ........................................................................................................................................ 19 
Sugar Dashlet Files ............................................................................................................................. 19 
Templating .......................................................................................................................................... 20 
Categories ........................................................................................................................................... 20 
Sugar Dashlet Base Class.................................................................................................................... 20 
Sugar Dashlets JavaScript ................................................................................................................... 21 
Browser JavaScript ................................................................................................................................. 22 
Accessing Language Pack Strings ...................................................................................................... 22 
Quicksearch......................................................................................................................................... 22 
ACL ........................................................................................................................................................ 23 
Scheduler................................................................................................................................................. 24 

Sugar Developer Guide 1


Contents 

Databases ................................................................................................................................................ 25 


Indexes ................................................................................................................................................ 25 
Primary Keys, Foreign Keys, and GUIDs........................................................................................... 26 
Logger ..................................................................................................................................................... 27 
Logger Level ....................................................................................................................................... 27 
Log File Name .................................................................................................................................... 28 
Log File Extension .............................................................................................................................. 28 
Log File Date Format .......................................................................................................................... 28 
Max Log File Size ............................................................................................................................... 28 
Max Number of Log Files................................................................................................................... 28 
Log Rotation ....................................................................................................................................... 28 
Web Services .......................................................................................................................................... 29 
Test Connection .................................................................................................................................. 29 
SugarSoap Login ................................................................................................................................. 29 
Get the Current User ID ...................................................................................................................... 30 
Get a list of records for a module ........................................................................................................ 31 
Get the values of a record ................................................................................................................... 32 
Set the values for a record ................................................................................................................... 33 
Get the fields for a module.................................................................................................................. 33 
Logout ................................................................................................................................................. 34 
SugarSoap Examples .......................................................................................................................... 34 
Chapter 3 Module Framework .................................................................................................................... 38 
Overview ................................................................................................................................................. 38 
User Interface Framework ...................................................................................................................... 38 
Model-View-Controller (MVC) Overview ......................................................................................... 38 
SugarCRM MVC Implementation ...................................................................................................... 39 
Metadata Framework .............................................................................................................................. 45 
Background ......................................................................................................................................... 45 
Application Metadata .......................................................................................................................... 46 
Module Metadata ................................................................................................................................ 46 
SearchForm Metadata ......................................................................................................................... 47 
DetailView and EditView Metadata ................................................................................................... 49 
SugarField Widgets ............................................................................................................................. 57 
    Contents 

Metadata Framework Summary .......................................................................................................... 69 


Vardefs .................................................................................................................................................... 70 
Dictionary Array ................................................................................................................................. 70 
Fields Array ........................................................................................................................................ 70 
Indices Array ....................................................................................................................................... 71 
Relationships Array ............................................................................................................................ 72 
Many-to-Many Relationships ................................................................................................................. 72 
Subpanels ................................................................................................................................................ 74 
One-to-Many Relationships ................................................................................................................ 74 
Many-to-Many Relationships ............................................................................................................. 75 
Relationship Metadata ........................................................................................................................ 75 
Layout Defs ......................................................................................................................................... 76 
Shortcuts ................................................................................................................................................. 77 
Chapter 4 Customizing Sugar ..................................................................................................................... 78 
Introduction ............................................................................................................................................. 78 
Tips & Pitfalls ..................................................................................................................................... 78 
The Custom Directory............................................................................................................................. 79 
Vardefs ................................................................................................................................................ 79 
Languages ........................................................................................................................................... 80 
Shortcuts Menu ................................................................................................................................... 81 
Layoutdefs........................................................................................................................................... 83 
Module Builder ....................................................................................................................................... 84 
Creating New Modules ....................................................................................................................... 84 
Understanding Object Templates ........................................................................................................ 85 
Editing Module Fields......................................................................................................................... 86 
Editing Module Layouts ..................................................................................................................... 87 
Building Relationships ........................................................................................................................ 88 
Publishing and Uploading Packages ................................................................................................... 89 
Adding Custom Logic using Code ...................................................................................................... 91 
Using the New Module ....................................................................................................................... 93 
Module Loader ........................................................................................................................................ 94 
Manifest Overview.............................................................................................................................. 94 
Installdef Definition ............................................................................................................................ 95 
Contents 

Upgrade Definition ............................................................................................................................. 97 


Sample Manifest ................................................................................................................................. 97 
Business Logic Hooks............................................................................................................................. 99 
Hook Definition ................................................................................................................................ 100 
Available Hooks................................................................................................................................ 100 
Options array ..................................................................................................................................... 103 
Packaging Custom Logic Hooks ....................................................................................................... 103 
Using Custom Logic Hooks .............................................................................................................. 104 
Tips & Pitfalls ................................................................................................................................... 104 
User Interface Customizations .............................................................................................................. 106 
Custom Grouping of Values ............................................................................................................. 106 
Custom Buttons ................................................................................................................................. 106 
Creating New Custom Displays ........................................................................................................ 107 
Overriding the View ......................................................................................................................... 107 
Creating a Custom SugarField .......................................................................................................... 108 
Adding QuickSearch to a Custom Field ........................................................................................... 109 
Tips & Pitfalls ................................................................................................................................... 111 
Creating New Sugar Dashlets ............................................................................................................... 112 
Custom Sugar Dashlets ..................................................................................................................... 113 
Creating Custom Chart Dashlets ....................................................................................................... 115 
Creating New Themes........................................................................................................................... 116 
Overview ........................................................................................................................................... 116 
Steps to Create a New Theme ........................................................................................................... 117 
Packaging Custom Themes ............................................................................................................... 118 
Tips & Pitfalls ................................................................................................................................... 120 
Adding Multiple Languages.................................................................................................................. 120 
Add a Language ................................................................................................................................ 120 
Creating Language Packs .................................................................................................................. 121 
Preface
Welcome to Sugar, an open source Customer Relationship Management (CRM) application. Sugar
enables organizations to efficiently organize, populate, and maintain information on all aspects of their
customer relationships. It provides integrated management of corporate information on customer accounts
and contacts, sales leads and opportunities, plus activities such as calls, meetings, and assigned tasks. The
system seamlessly blends all of the functionality required to manage information on many aspects of your
business into an intuitive and user-friendly graphical interface.

Sugar also provides a graphical dashboard to track the sales pipeline, the most successful lead sources,
and the month-by-month outcomes for opportunities in the pipeline.

Sugar is based on an open source project and therefore advances quickly through the development and
contribution of new features by its supporting community.

Welcome to the community!

About this Guide


The Sugar Developer Guide is designed for developers who are new to Sugar, or to CRM and Web-based
applications. This guide introduces you to some basic CRM concepts and helps you get familiar with the
Sugar system. It describes how to install and upgrade Sugar and access it through a personal computer
and a Web browser to perform a broad range of customer relationship management tasks.

Readers are expected to have basic programming and software development knowledge, be familiar with
the PHP programming language and the SQL database language.

Audience
The Sugar Developer Guide provides information for developers who want to extend and customize
SugarCRM functionality using the customization tools and API’s provided in the Sugar Community
Edition, Sugar Professional Edition and Sugar Enterprise Edition.

Overview
Sugar consists of modules which represent a specific functional aspect of CRM such as Accounts,
Activities, Leads, and Opportunities. For example, the Accounts module enables you to create and
manage customer accounts, while the Activities module enables you to create and manage activities
related to accounts, opportunities, etc. Sugar modules are designed to help you manage your customer
relationships through each step of their life cycle, starting with generating and qualifying leads, through
the selling process, and on to customer support and resolving reported product or service issues. Because
many of these steps are interrelated, each module displays related information. For example, when you
view the details of a particular account, the system also displays the related contacts, activities,

Sugar Developer Guide 5


Preface 

opportunities, and bugs. You can not only view and edit this information but can also create new
information.

As a developer, Sugar gives you the ability to customize and extend functionality within the base CRM
modules. You can customize the look and feel of Sugar across your organization. Or you can create
altogether new modules and build entirely new application functionality to extend these new modules.

Core Features
Sales Management
• Lead, Contact, and Opportunity Management to share information and pursue new
business.

• Account management to manage all customer interactions in a single location.

Marketing Automation
• Lead management for tracking and cultivating new leads.

• Email marketing for touching prospects and customers with relevant offers.

• Campaign management for tracking campaigns across multiple channels.

• Campaign reporting to analyze the effectiveness of marketing activities

Collaboration
• Activity management for Emails, tasks, calls, and meetings

• Content syndication to consolidate third-party information sources.

News Service
• The RSS news feeds module lets you select and manage your favorite news feeds, and
display them on your My RSS News Feeds screen.

Administration
• Quickly edit user settings, views and layouts in a single location.

• Customize the application with Sugar Studio so that Sugar meets the exact needs of your
company.

Interface Consolidation
The My Portal module allows administrators and users to link external web sites and web
applications into the Sugar User Interface, enabling Sugar to become a unified information
interface for its users.

Sugar is built on established open-source technologies and widely supported industry standards,
including the PHP development environment, the MySQL relational database, the Apache or IIS

6 Sugar Developer Guide


    Preface 

web servers, and the Linux or Windows Server operating systems. The system supports both the
LAMP (Linux, Apache, MySQL, PHP) and WIMP (Windows, IIS, MySQL, PHP) platforms.

What’s New in 5.1


With each revision of the Sugar software, significant advances are made in both the feature set and
usability of the software.

Enhanced Emails Functionality


With the IMAP protocol, you can limit access to specific folders on your external account.

Enhanced Import Functionality


You can now import data for the Bug Tracker. Also, you can enable the import functionality for
any custom module that you build in Module Builder. You can save field mappings between the
import file and the Sugar database for future use.

Creating Relationships Between Modules


You can create relationships between modules in Module Builder as well as Studio. In Module
Builder, you can create relationships between two undeployed modules, and between one
undeployed module and one deployed module. In Studio, you can create relationships only
between deployed modules.

Embedding Links and IFrames in a Layout


A Link field allows you to store a URL in a record such as a customer's Website or a link to a
related internal or external system. You can also embed a view of the Website itself in the layout
rather than as a link by using the IFrame field.

Locking Down the Upgrade Wizard


If you are managing multiple instances of the Sugar application and you want to maintain
complete control over the instances, you can lock down the Upgrade Wizard to ensure that no
user with administrative privileges can upgrade any of them.

Locking Down the Module Loader


In order to ensure that users with administrative privileges do not load sub-standard modules into
your Sugar application, you can lock down the Module Loader and direct them to load modules
from a location of your choice.

Related Documentation
Refer to the following guides for related information:

• Sugar User Guide: Describes how to use Sugar modules.

• Sugar Installation and Administration Guide: Describes how to install, set up, configure, and
manage Sugar.

Sugar Developer Guide 7


Preface 

• Sugar Upgrade Guide: Describes how to upgrade to the latest version of Sugar application.

8 Sugar Developer Guide


Chapter 1 SugarCRM Overview

Platform Overview
SugarCRM was originally written on the LAMP stack (Linux, Apache, MySQL and PHP). Since version
1.0, the SugarCRM development team has added support for every operating system that the PHP
programming language runs on (including Windows, Unix and Mac OSX), for the Microsoft IIS Web
server and for the Microsoft SQL Server and Oracle databases. Designed as the most modern Web-based
CRM platform available today, SugarCRM has quickly become the business application standard for
companies around the world. See the Supported Platforms page for detailed information on supported
software versions and recommended stacks.

SugarCRM is available in three editions: the Community Edition, which is freely available for download
under the GPLv3 public license, and the Professional and Enterprise Editions, which are sold under a
commercial subscription agreement. All three editions are developed by the same development team
using the same source tree with extra modules available in the Professional and Enterprise Editions.
Sugar customers using the Professional and Enterprise Editions also have access to Sugar Support,
Training and Professional Services offerings. Contributions are happily accepted from the Sugar
Community, but not all contributions are included as SugarCRM maintains high standards for code
quality.

From the very beginning of the SugarCRM Open Source project in 2004, the SugarCRM development
team designed the application source code to be examined and modified by developers. The SugarCRM
application framework has a very sophisticated extension model built into it allowing developers to make
significant customizations to the application in an upgrade-safe and modular manner. While it may be
easy to modify one of the core files in the distribution, you should always check to see first if there is an
upgrade-safe way to make your changes. Educating developers on how to make upgrade-safe
customizations is one of the key goals of this Developer Guide.

Application Framework Overview


The SugarCRM application code is based on a modular framework with secure entry points into the
application (e.g. index.php or soap.php). All modules, whether core modules or ones you create and
install through the Module Loader, must exist in the <sugar root>/modules/ folder. Typically modules
represent business entities or objects in SugarCRM, such as ‘Contacts’, and the object has fields or
attributes that are stored in the database, as well as a user interface (UI) for the user to create and modify
records. A module encompasses definitions for the data schema, user interface and application
functionality.

Sugar Developer Guide 9


Chapter 1   SugarCRM Overview 

10 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

Figure 1: Sugar root directory structure

Directory Structure
SugarCRM code resides in various directories within the Sugar installation. The structure of the
directories within the Sugar application consists of the following root level directories:

• cache: Various cache files written to the file system to minimize database accesses and store
user interface templates created from metadata. Also files uploaded into the application such
as Note Attachments or Documents reside in this directory (refer to ‘upload_dir’ parameter in
the config.php file) which means that this is an active cache directory and not all files can be
deleted from this directory.

• custom: Stores upgrade-safe customizations such as custom field definitions, user interface
layouts and business logic hooks.

• data: Key system files are located here, most notably the SugarBean base class which
controls the default application logic for all business objects in Sugar.

• include: Many Sugar utility functions are located here as well as other libraries that Sugar
utilizes as part of its operations. Most notably in this directory is the utils.php file that
contains all of the most widely used utility functions.

• metadata: This file contains relationship metadata for all many-to-many data relationships
between the business objects.

• modules: This folder contains all modules in the system. Custom modules installed through
the Module Loader exist here as well.

Key Concepts
These are the main files, classes and application concepts that comprise the Sugar platform.

Application Concepts
• Controller: Directs all incoming page requests. It can be overridden in each module to
change the default behavior. It relies on Entry point parameters - described below - to serve
the appropriate page.

• Views: A set of user interface actions managed by the Controller, the default views in Sugar
include the DetailView, EditView and ListView.

• Display Strings: SugarCRM is fully internationalized and localizable. Every language pack
has its own set of display strings which is the basis of language localization. There are two
types of display strings in the Sugar application: application strings and module strings.
Application strings contain the user interface labels displayed globally throughout the
application. The $GLOBALS[‘app_strings’] array contains these labels. There is also the
$GLOBALS[‘app_list_strings’] array which contains the system-wide dropdown list
values. Each language has its own application strings variables. The

Sugar Developer Guide 11


Chapter 1   SugarCRM Overview 

$GLOBALS[‘mod_strings’] array contains strings specific to the current, or in-focus,


module..

• Dropdown Lists: Dropdown lists are represented as ‘name’ => ‘value’ array pairs located in
the application strings as mentioned above. The ‘name’ value is stored in the database where
the ‘value’ is displayed to the user in the UI. You are able to create and edit dropdowns and
their values via the UI in the admin Studio tool. For working with dropdown lists in
EditViews use the handy get_select_options_with_id() utility function to help render the
<select> input options. Also use the handy translate() utility function for translating
whatever string key you are working with into the user’s currently selected display language.

Files
• SugarBean.php: This file located under the ‘<sugar root>/data’ folder contains the
SugarBean base class used by all business entity or module objects. Any module that reads,
writes or displays data will extend this class. The SugarBean performs all of the heavy lifting
for data interactions, relationship handling, etc.

• modules.php: The modules.php file is a critical file in Sugar. It contains several variables
that define which modules are active and usable in the application.

Variables
• $dictionary: The $dictionary array contains all module field variable definitions (vardefs), as
well as the relationship metadata for all tables in the database. This array is dynamically built
based upon the vardefs.php definitions.

Entry Points
The primary user interface entry point for Sugar is through index.php located in the root Sugar
folder. There are three main parameters for most calls within Sugar, they are:

• module: The module to be accessed as part of the call

• action: The action to be taken by the application within the module

• record: The record id to be accessed

An example URL for a Sugar call might be:

http://www.yoursugarsite.com/index.php?module=Contacts&action=DetailView&record=d545d1dd-
0cb2-d614-3430-45df72473cfb

This URL invokes the DetailView action from within the Contacts module to display the record
denoted by the record request value.

Other commonly used parameters are ‘return_module’, ‘return_action’, return_id’. This group of
request parameters are typically used when a user selects to cancel out of an action such as when
creating/editing a record.

12 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

Note: For version 5.1 most entry points were consolidated into index.php. Previous versions had
other files as entry points into the application.

Module Framework Overview


All modules, whether core modules or ones you create and install through the Module Loader are placed
in the <sugar root>/modules/ folder. Typically modules are created when you have to represent an object
in Sugar, such as ‘Contacts’, and the object has data points that need to be stored in the database, as well
as have an UI for the user to create, edit, and delete records for the object.

Let us look at a modules framework and how it fits into the overall Sugar Platform.

In the Platform Overview section, we show an example of a call that would be typical for a DetailView
action within a particular module. There are five main actions for a module:

• ListView: This Controller action exists to provide the user with the search form and search
results for a module. From this screen, a user can take such actions as deleting, exporting, and
mass updating multiple records or drill into a specific record to view and edit the details. The user
is dropped into this view by default when he clicks on one of the tabs at the top of the application.
Files in each module describe the contents of the list and search view.

• DetailView: A DetailView provides a read-only detail view of a particular object. Typically, a


user will access a record’s DetailView via a ListView. The user can view the details of the object
itself and, below the details, will see lists of related items that are referred to as ‘SubPanels’ in
Sugar. SubPanels act as mini-ListViews of items that are related to the parent object accessed
with the DetailView action. For instance, Tasks assigned to a Project or Contacts to an
Opportunity will appear in SubPanels below the Project or Opportunity.
<module>/metadata/detailviewdefs.php defines a module's DetailView page's layout.
<module>/metadata/subpaneldefs.php defines the subpanels that are visible under the module's
DetailView page.

• EditView: The EditView action is accessed whenever a user is creating a new record or editing
details of an existing one. It is possible to directly access the EditView from the ListView.
<module>/metadata/editviewdefs.php defines a module's EdtiView page's layout.

• Save: This Controller action is processed whenever the user clicks the ‘Save’ button from the
EditView of a record.

• Delete: This action is processed whenever the user clicks the ‘Delete’ button from the DetailView
of a record or, as a special case, from an item listed in a SubPanel.

These actions are driven by the UI framework, and the framework relies on metadata files in the requested
module.

• <module>/metadata/listviewdefs.php describes the layout of the ListView.

Sugar Developer Guide 13


Chapter 1   SugarCRM Overview 

• <module>/metadata/searchdefs.php describes the search form tabs above the ListView.

• <module>/metadata/editviewdefs.php describes the layout of the EditView.

• <module>/metadata/detailviewdefs.php describes the layout of the DetailView.

Besides the action files described above you probably have noticed some additional files located in the
folder.

• forms.php: This file contains two functions to render specific JavaScript for validation or other
actions you might want to perform during edits/saves. By default you can leave these empty and
have them return ‘’;

• Menu.php: This file is responsible for the rendering of shortcuts menu you typically see on the
left hand side of the screen. By default you usually add a link to create a new record, and a link to
the ListView to search.

• Popup.php: This file acts as a wrapper to the central Popup class located under the utils folder. It
is called if ever another module wants to get a popup list of records from a related module. The
central Popup class then uses the Popup_picker.html and
<MODULE_NAME>/metadata/popupdefs.php file to render the popup.

• Popup_picker.html: Used by the central Popup class to display a module’s popup.

• vardefs.php: The vardefs.php metadata file defines db and non-db fields for Sugar objects as
well as relationships between objects.

• field_arrays.php: This file is deprecated as of Sugar version 5.1. It has been phased out over
time with the addition of additional metadata structures in the application, most notably the
vardefs metadata.

Now let us look at the various subfolders within a module folder to complete the overview of the module
structure.

14 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

• Sugar Dashlets: Sugar Dashlets are drag-and-drop forms displayed on the Sugar Home and
Dashboard tabs. These forms can display any data, including data pulled from external data
sources. With the Sugar default application, they contain ListView and Chart data for the
application modules. As a developer of a custom module you are able to create a Sugar Dashlet
view to your new module. For each Sugar Dashlet you create, you will place the necessary files in
the ‘<MODULE_NAME>/Dashlets’ folder.

• language: The language folder’s main purpose is to hold the strings files for the your module. By
default you will have an en_us.lang.php file which contains ALL strings used specifically by your
module. These strings are represented by the $mod_strings variable which can be accessed at
any time after a global $mod_string call. The .html files located in this folder are used by the
Help subsystem. Sugar provides the capabilities for multi-language support and the dynamic
loading via the admin panel of new language packs.

• metadata: As more and more metadata and extensibility has been built into the Sugar Platform,
module-specific metadata files have been added to this folder. Some of the most important files in
this directory include: additionaldetails.php defines the content of the popup displayed in the
ListViews; listviewdefs.php defines the columns displayed in the module ListView page;
popupdefs.php defines the search fields and list columns for a module’s popup; SearchFields.php
defines the Basic Search and Advanced Search forms seen in the ListView page; studio.php
defines how the Studio tool interacts with a module's metadata files.

• subpanels: This folder will hold the definitions of a module’s SubPanels when that module is
related in a one-to-many or many-to-many fashion. Typically you have the default.php file. You
can add any number of versions here. Alternatively, you can also create custom versions of

Sugar Developer Guide 15


Chapter 1   SugarCRM Overview 

SubPanels of other modules to be displayed by your custom module. For example, with your
custom module you could make relate it with the Contacts module and have a Contacts SubPanel
under your DetailView. For instance, you could build and place a ‘ForWidgets.php’ file under the
‘<sugar root>/modules/Contacts/subpanels/’ folder. The file name is referenced by the
‘subpanel_name’ parameter called from a ‘layout_defs.php’ definition.

• tpls: This folder holds Smarty template files. Currently the only specific use of this is for the
Quick Create forms.

• views: In this folder are files that can override the default Model-View-Controller (MVC)
framework view files. View files can perform multiple different actions on the Smarty template
or outputted HTML, allowing developers to modify and extend the default UI display classes and
take full control of the user interface.

User Interface Framework Overview


SugarCRM uses an implementation of the Model-View-Controller (MVC) pattern the base of all
application interactions. Working closely with the MVC framework is a metadata-driven UI framework
where the high-level specification of parts of the user interface in the application is described in a
metadata structure.

Extension Framework Overview


The extension framework in Sugar allows you to implement customizations of existing modules or create
entirely new modules. Through the various extension framework capabilities you can extend most of the
functionality of Sugar in an upgrade-safe manner. The Module Builder tool and Studio tool available in
the Admin screen allows you to make the most common customizations outlined below. You can then
further extend your system by adding upgrade-safe custom code. The areas open to extension are:

• Modules: You are to create entirely new modules and add them to Sugar.

• Vardefs: You are able to add custom fields to existing modules with the addition of your custom
module.

• Relationships: New relationships can be added to the system between your new modules and
existing modules in Sugar.

• SubPanels: With the addition of new relationships you can create/add new SubPanel definitions
to existing modules.

• Strings: Module and application strings can be added or overridden.

• Menus: Shortcut menus can be added to or overridden

16 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

• Layout Defs: Which subpanels are displayed, and in which order they are displayed can be
altered. Not only can you create the layout_def for you newly added module, but you can also
edit the layout_def of an existing module to add your new module as a subpanel.

Sugar Dashlets Overview


Sugar Dashlets is a framework that provides for Sugar Dashlet containers to be included in the Sugar UI.
Sugar Dashlet container objects can display and interact with Sugar module data, with external sources
like RSS feeds and with web services like Google Maps. Released originally in Sugar 4.5, Sugar Dashlets
are a powerful new way to combine highly functional mash-ups in an attractive and easily tailored AJAX-
based UI framework. Sugar Dashlets are located on the home page and Dashboard page and allow for the
customization via simple drag-and-drop tools. The Sugar Dashlet Framework allows developers to easily
create new Sugar Dashlets that are installable into SugarCRM instances via the Module Loader.

Web Services Overview


SugarCRM provides a Web Services API interface for developers to build integrations with SugarCRM
for reading and writing data. SugarCRM provides Web Services API’s via the NuSOAP PHP
implementation of the SOAP protocol. SOAP stands for "Simple Object Access Protocol." It is used for
making Remote Procedure Calls through the HTTP protocol by relaying messages in XML. The
SugarSoap API’s, built on top of the NuSOAP PHP library, are included in the Sugar Community, Sugar
Professional and Sugar Enterprise editions.

Sugar Developer Guide 17


Chapter 2 Application Framework

Entry Points
All entry points into the Sugar application are pre-defined so that proper security and authentication steps
are applied consistently across the entire application.

• campaign_tracker.php – used by the Campaign Management module for tracking campaign


responses. Deprecated as of Sugar 5.1.0.

• cron.php – used by the Windows Scheduler Service or the cron service on Linux and Unix for
executing the Sugar Scheduler periodically.

• index.php – default entry point into the Sugar application

• install.php – used for initial install

• maintenance.php – invoked when the application is down for maintenance.

• metagen.php - Deprecated as of Sugar 5.1.0.

• silentUpgrade.php – used for silent installer

• soap.php – entry point for all SOAP calls

• vcal_server.php – used for syncing information to Outlook

File Caching
Much of the user interface is built dynamically via templates from metadata and language string files.
SugarCRM implements a file caching mechanism to improve the performance of the system by reducing
the number of static metadata and language files that need to be resolved at runtime. This directory stores
the cached template and language string files.

When developing in SugarCRM, we suggest that you turn on Developer Mode (Admin->System
Settings->Advanced->Developer Mode) which causes the system to ignore these cached files. This is
especially helpful when you are altering templates, metadata or language files directly. When using
Module Builder or Studio, the system will automatically refresh the file cache. Be sure to turn Developer
Mode off when you have completed your customizations as Developer Mode does degrade system
performance.

Sugar Developer Guide 18


Chapter 1   SugarCRM Overview 

Sugar Dashlets
Sugar Dashlets use the abstract factory design pattern. Individual Dashlets extend the base abstract class
Dashlet.php, ListView Dashlets extend the base abstract classDashletGeneric.php, while chart Dashlets
extend the base abstract class DashletGenericChart.php.

Sugar Dashlet instances must be contained in one of the following directories:

• modules/moduleName/Dashlets/

• custom/modules/moduleName/Dashlets/

Typically, Sugar Dashlet developers will want to use the custom/ directory in order to make their Sugar
Dashlets upgrade-safe. The standard modules/ directory location is where you'll find Sugar Dashlets
offered in base Sugar releases.

Sugar Dashlet Files


The file name containing the main Sugar Dashlet code must match the Sugar Dashlet’s class name.
For example, the Sugar Dashlet class JotPadDashlet will be found in the file
/Home/Dashlets/JotPadDashlet/JotPadDashlet.php. The JotPadDashlet Dashlet is a sample Sugar
Dashlet released originally in Sugar 4.5. It serves as a useful example from which to begin your
development efforts.

A metadata file accompanies each Sugar Dashlet. It contains descriptive information about the Sugar
Dashlet as defined here:

$DashletMeta['JotPadDashlet'] = array(
'title' => 'LBL_TITLE',
'description' => 'LBL_TITLE',
'icon' => 'themes/Sugar/images/Accounts.gif',
'category' => 'Tools');

The naming convention for the metadata file is className.meta.php, where className is the name of
your Sugar Dashlet, and it must appear in the same directory as the Sugar Dashlet code. For
JotPadDashlet the meta file is stored in
/Dashletsmodules/Home/Dashlets/JotPadDashlet/JotPadDashlet.meta.php.

The ‘title’ and ‘description’ elements are translated. If the values here match a key in the array
$DashletStrings (from the language file) then they will be translated otherwise it will display the
literal string. (It is best practice to use translatable language strings so that your Sugar Dashlet is
international!)

Language files have a similar naming convention: className.locale.lang.php (e.g.,


/Dashletsmodules/Home/Dashlets/JotPadDashlet/JotpadDashlet.en_us.lang.php )

Icon files can either be defined in the .meta data file or simply included in the Sugar Dashlet
Directory (e.g., /Dashletsmodules/Home/Dashlets/JotPadDashlet/JotPadDashlet.icon.png). The
system will scan for image files in the corresponding Sugar Dashlet directory.

Sugar Developer Guide 19


Chapter 1   SugarCRM Overview 

Templating
The suggested templating engine for Sugar Dashlets is Smarty, however it is not required.

Categories
There are 5 categories for Sugar Dashlets.

• Module Views – Generic views of data in modules

• Portal – Sugar Dashlets that allow access to outside data (rss, Web services, etc)

• Charts – Charts of data

• Tools – Various tools like a notepad, calculator, or even a world clock!

• Miscellaneous - Any other Sugar Dashlets

Sugar Dashlet Base Class


The main Sugar Dashlet base class is include/Dashlets/Dashlet.php. All Sugar Dashlets should extend
this class.

class Dashlet {
// guid of the Dashlet, assigned on creation of the Dashlet
var $id;
// Title of the Dashlet
var $title = 'Generic Dashlet';
// true if the Dashlet has configuration options.
var $isConfigurable = false;
// true if the Dashlet contains JavaScript
var $hasScript = false;
// Language strings, must be loaded at the
// Dashlet level w/ loadLanguage
var $DashletStrings;

function Dashlet($id) {
$this->id = $id;
}
Each Sugar Dashlet upon creation must be assigned a unique id. This id is used in the HTML id when
the Sugar Dashlet is displayed. This way multiple Sugar Dashlets of the same type can be included on
the page.

// Title portion of the Dashlet, $text is any text to be put


// in between the title and the Close icon
function getTitle($text) { ...}

// Displays the actual Dashlets


// *Inheriting Dashlet should override this
function display($text = '') { ... }

// Displays the Dashlets options


// *Inheriting Dashlet should override this if isConfigurable
function displayOptions() { … }

// override if you need to do pre-processing before


// display is called

20 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

function process() {
}

// Override this if your Dashlet is configurable


// (this is called when the configureDashlet form is shown)
function saveOptions($req) {
}
is called when the configuration form is submitted. This function need to filter out
saveOptions()
the $_REQUEST array and only return an array of the options that needs to be saved

// loads language strings from files and stores them


// $DashletStrings. This will try to load the current language
// file first, then default of en_us
function loadLanguage($DashletClassname, $DashletDirectory) { ... }

// Generic way to store Dashlet options into user preferences


function storeOptions($optionsArray) { ... }

// Generic way to load Dashlet options from user preferences


function loadOptions() { ... }

Sugar Dashlets are stored in the table user_preferences under the name ‘Dashlets’ and the category
‘home’. Here is a sample array element of ‘Dashlets’ from the MyOpportunitiesDashlets

[425f8ca8-663c-dabe-b483-448f6e4fb9a8] => Array


(
[className] => MyOpportunitiesDashlet
[fileLocation] =>
/Dashlets./modules/Opportunities/Dashlets/MyOpportunitiesDashlet/MyOpportunitiesDashle
t.php
[options] => Array
(
[filters] => Array
(
)

[title] => My Top Open Opportunities


[myItemsOnly] => true
[displayRows] => 5
[displayColumns] => Array
(
[0] => name
[1] => amount
[2] => team_name
)

)
The ‘options’ element stores the options for the Sugar Dashlet and this is the element that is
loaded/stored by storeOptions / loadOptions functions in the base Dashlet class.

Sugar Dashlets JavaScript


Sugar Dashlet utility functions are located in include/JavaScript/Dashlets.js. This contains the
following methods:

postForm: function(theForm, callback) {}

Sugar Developer Guide 21


Chapter 1   SugarCRM Overview 

postForm method is used to post the configuration form via AJAX. The callback will usually be
SUGAR.sugarHome.uncoverPage to remove the configuration dialog.

callMethod: function(DashletId, methodName, postData, refreshAfter, callback) {}

callMethod is a generic way to call a method in a Dashlet class. Use this function to generically call
a method within your Dashlet class (php side). Optionally, you can refresh your Dashlet after a call
and also utilize a callback function.

This method can also be used as a way to proxy AJAX calls to Web services that don’t exist on the
SugarCRM install. (Google Maps Mash-ups for example.)

Browser JavaScript
As Sugar is a Web-based application, executing custom logic on the client-side (e.g., validating data
before posting it back to the server) requires writing JavaScript. This section outlines the JavaScript
constructs available to the developer.

In order to improve application performance, Sugar's production JavaScript files are compressed with the
JSMin library. This process reduces JavaScript file sizes, thereby reducing download times. The
originally formatted JavaScript files are in the /jssource directory. It is a best practice to make any
JavaScript code changes in the /jssource/src_files folders and then use the “Rebuild JS Compressed Files”
option in Admin->Repair.

Accessing Language Pack Strings


All language pack strings are accessible within the browser-side JavaScript. To access these strings
simply use the following JavaScript call:

// LBL_LOADING string stored in $app_strings


SUGAR.language.get('app_strings', 'LBL_LOADING');

// LBL_LIST_LAST_NAME string stored in Contacts $mod_strings


SUGAR.language.get('Contacts', 'LBL_LIST_LAST_NAME');

Admins and translators will need to be aware that these JavaScript language files are cached. If there
are any changes to the language files they will need to 'rebuild' the JavaScript files from the Repair
console in the admin section. This essentially removes the cache files and they will be rebuilt when
needed. It also increments js_lang_version in sugar_config so that user's browser will re-cache these
js files.

Quicksearch
Sugar 5.1 uses a type-ahead combo box system we call QuickSearch based around ExtJS. The Sugar
QuickSearch (SQS) code resides in the file <sugar_root>/include/javascript/quicksearch.js. The
ExtJS library which drives the QuickSearch is located at <sugar_root>/include/javascript/ext-2.0/ext-
quicksearch.js. These two files are grouped in <sugar_root>/include/javascript/sugar_grp1.js which
is loaded in all the main page of SugarCRM. A custom Ext ComboBox is used to pull data via an

22 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

AJAX call to http://yourserver/SugarCRM/index.php which then accesses the file


<sugar_root>/modules/Home/quicksearchQuery.php.

Note: Sugar versions 4.5.1 – 5.0.0 use a system based on wick. Sugar 4.5.0 and prior use
<sugar_root>/json_server.php.

The browser will initiate an AJAX call via JavaScript to the server 700ms after the last user input
takes place in the browser. A call is then made requesting up to 30 results per result set.

The first twelve results are then displayed to the user in the browser. If the user refines his search and
the result set is a subset of the first call then no additional call is made. If the result set of the first call
is equal to the limit (30), then an additional call will be made.

Requirement for a QuickSearch Field:

ƒ The class of the field has to be set to "sqsEnabled".

ƒ The field must not be set to "disabled" nor "readOnly".

ƒ The "sqs_objects" JS array has to be defined and has to contain the field name.

ƒ "sugar_grp1.js" has to be loaded on the page.

Custom Parameter :

sqsNoAutofill : add this string to the class of the field to disable the Automatic filling of the field on
Blur.

Metadata example:

array(
'name' => 'account_name',
'displayParams' => array(
'hiddeButtons'=>'true',
'size'=>30,
'class'=>'sqsEnabled sqsNoAutofill'
)
),

ACL
ACLs, or Access Control Lists, are used to restrict access to Sugar modules, and the data and actions
available (e.g., “Delete” and “Save”) to users within Sugar modules. ACLs are defined in the Roles area
of Sugar Admin. Sugar Professional and Enterprise Editions restrict user access down to specific fields.

You can check whether the current user has access to a particular action using the following code:

if (ACLController::checkAccess($category, $action, $is_owner, $type)) {


// your code here
}

Sugar Developer Guide 23


Chapter 1   SugarCRM Overview 

Where the parameters mean the following:

• $category = this corresponds to the module directory where the bean resides. For example:
Accounts

• $action – the action you want to check against. For example: edit. These correspond to actions in
acl_actions table as well as actions performed by the user within the application.

• $is_owner – whether or not the owner of the record attempting an action. Defaults to false. This
only comes into play when the access level = ALLOW_OWNER

• $type = this defaults to ‘module’ and for all intents and purposes a developer does not need to
pass this in or can pass in ‘module’. This would only be used for special purposes to allow for
additional out of the box access levels.

See the ‘Roles’ feature in the Sugar Installation and Administration Guide for the list of actions and their
possible values.

Scheduler
SugarCRM contains a Scheduler service that asynchronously executes predefined functions on a periodic
basis. The Scheduler integrates with external UNIX systems and Windows systems to run jobs that are
scheduled through those systems. The usual configuration is to have a UNIX cron job or a Windows
scheduled job execute the SugarCRM Scheduler service every couple minutes. The Scheduler service
checks the list of Schedulers defined in the Scheduler Admin screen and executes any that are currently
due.

A series of Schedulers are defined by default with every SugarCRM installation such as “Process
Workflow Tasks” and “Run Report Generation Scheduled Tasks”.

24 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

Databases
Sugar Community Edition and Sugar Professional Edition support the MySQL and Microsoft SQL Server
databases. In addition to these two databases, Sugar Enterprise Edition supports the Oracle database. In
general, Sugar uses only common database functionality, and application logic is embedded in the PHP
code. This means that Sugar uses no database triggers or stored procedures. This design approach
simplifies coding and testing across different database vendors. Therefore the only implementation
difference that you will typically find across the various supported databases is column types.

Sugar uses the mysql PHP extension for MySQL support (or mysqli if it enabled), the mssql extension for
Microsoft SQL Server support, and the oci8 extension for Oracle support. Sugar does not support generic
ODBC access or other database drivers such as PDO.

Indexes
Indexes can be defined directly in the main or custom vardefs.php for module, in an array under the
key 'indices'. Below is the example of defining several indices:

'indices' => array (


array(
'name' => 'idx_modulename_name',
'type' => 'index',
'fields' => array('name'),
),
array(
'name' => 'idx_modulename_assigned_deleted',
'type' => 'index',
'fields' => array('assigned_user_id', 'deleted'),
),
),

Sugar Developer Guide 25


Chapter 1   SugarCRM Overview 

The name of the index should start with idx_ and be unique across the database. The possible values
for ‘type’ include 'primary' for a primary key or 'index' for a normal index. The fields list matches the
column names used in the database.

Primary Keys, Foreign Keys, and GUIDs


By default, Sugar uses globally unique identification values (GUIDs) for primary keys for all
database records. Sugar provides a create_guid() utility function for creating these GUIDs in the
following format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee. The primary key column length is 36
characters.

The GUID format and value has no special meaning in Sugar other than the ability to match records
in the DB. Sugar links two records (such as an Account record with a Contact record) with a
specified ID in the record type relationship table (e.g. accounts_contacts).

Sugar allows a primary key to contain any unique string. This could either be a different GUID
algorithm, a key that has some meaning (such as bean type first, followed by info), an external key,
and/or auto-incrementing numbers (converted to strings). The Sugar development team chose GUIDs
rather than auto-incrementing keys to allow for easier data synchronization across databases (in order
to avoid primary key collisions). This data synchronization issue comes into play when the Sugar
Offline Client (part of Sugar Enterprise) syncs data between the main Sugar installation and the
Offline Client or when developers use the Sugar SOAP APIs or a tool like Talend for data
synchronization.

The strategy of the Offline Client using GUIDs for primary keys is elegant in that it is very easy to
implement and handling data conflicts is simpler than with other schemes. If a developer changes
Sugar to use some other ID scheme and does need to accommodate data synchronization across data
stores, then he would have to either partition the IDs ahead of time or work out a system similar to the
Sugar implementation for Cases, Quotes and Bugs. For these modules, which have human-readable
ID numbers (integers) that need to be synchronized across databases, Sugar implements a server ID
that is globally unique and concatenates that with an incrementing Case, Quotes or Bug number.
Attempting such a change to Sugar, while certainly possible, would require some careful planning
and implementation.

However if the developer does not need to worry about data synchronization issues, then he can
certainly change the primary key format to some other unique string.

Also, it is not a problem to import data from a previous system with one primary key format and then
simply have all new records in Sugar use the GUID primary key format. All keys simply need to be
stored as unique strings with no more than 36 characters.

To implement a new primary key method or to import existing data with a different primary key
format and then rely on the existing GUID mechanism for new records, there are a few things to look
out for:

• The system expects primary keys to be string types and will format the SQL with quotes. If
you change the primary key types to an integer type, you might have SQL errors to deal with

26 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

since we put all ID values in quotes in our generated SQL. The database might be able to
ignore this issue. MySQL running in Safe mode will have issues for instance.

• Case-sensitivity can be an issue. IDs “abc” and “ABC” are typically treated the same in
MySQL but represent different values in Oracle. Some other CRM systems from which
people were migrating to SugarCRM were using case sensitive strings as their IDs on export.
If this is the case, and you are running MySQL, you need to run an algorithm on the data to
make sure all of the IDs are unique. One simple algorithm is to MD5 the ids that they
provide. A quick check will let you know if there is a problem. If you imported 80,000 leads
and there are only 60,000 in the system, some might have been lost due to non-unique
primary keys resulting from this case-sensitivity issue.

• Sugar only tracks the first 36 characters in the primary key. Any replacement primary key
will either require changing all of the ID columns with one of an appropriate size or to make
sure you don’t run into any truncation or padding issues. MySQL in some versions has had
issues with Sugar where the IDs were not matching because it was adding spaces to pad the
row out to the full size. MySQL’s handling of char and varchar padding has changed in some
of the more recent versions. To protect against this, you will want to make sure the GUIDs
are not padded with blanks in the DB.

Logger
The Sugar Logger allows developers and system administrators to log system events and debugging
information into a log file. The Sugar code contains log statements at various points which are triggered
based on the logging level.

For example, to write a message to the sugarcrm.log file when the log level is set to ‘fatal’, put the
following into your code:

$GLOBALS['log']->fatal('my fatal message');

Logger Level
The logger level determines how much information is written to the sugarcrm.log file. You will find
the sugarcrm.log file in the root of your Sugar installation.

Valid values are 'debug', 'info', 'error', 'fatal', 'security', and 'off'. The logger will log information for
the specified and higher logging levels. For example if you set the log level to 'error' then you would
see logs for 'error', 'fatal', and 'security'. You also may define your own log levels on the fly. For
example if you set the value to 'test' then only values logged to $GLOBALS['log']->test('This is
my test log message'); would be logged. You should avoid using the logging level of ‘off’. The
default value is 'fatal'.

$GLOBALS['sugar_config']['logger']['level'] = 'debug';

You can also force the log level in your code by using:

Sugar Developer Guide 27


Chapter 1   SugarCRM Overview 

$GLOBALS['log']->setLevel('debug');

Log File Name


You may concatenate static strings, variables and function calls to set this value. For example if you
wish to have monthly logs set this to 'sugarcrm' . date('Y_m') and every day it will generate a
new log file. The default value is 'sugarcrm'.

$GLOBALS['sugar_config']['logger']['file']['name']

Log File Extension


The defaults value is '.log'. Therefore the full default log file name is ‘sugarcrm.log’.

$GLOBALS['sugar_config']['logger']['file']['ext']

Log File Date Format


The date format for the log file is any value that is acceptable to the PHP strftime() function. The
default is '%c'. For a complete list of available date formats, please see the strftime() PHP
documentation.

$GLOBALS['sugar_config']['logger']['file']['dateformat']

Max Log File Size


This value controls the max file size of a log before the system will roll the log file. It must be set in
the format '10MB' where 10 is number of MB to store. Always use MB as no other value is currently
accepted. To disable log rolling set the value to false. The default value is '10MB'.

$GLOBALS['sugar_config']['logger']['file']['maxSize']

Max Number of Log Files


When the log file grows to the 'maxSize' value, the system will automatically roll the log file. The
'maxLogs' value controls the max number of logs that will be saved before it deletes the oldest. The
default value is 10.

$GLOBALS['sugar_config']['logger']['file']['maxLogs']

Log Rotation
The Sugar Logger will automatically rotate the logs when the 'maxSize' has been met or exceeded. It
will move the current log file to <Log File Name> . 1 . <Log Extension>. If <Log File Name> . 1 .
<Log Extension> already exists it will rename it to <Log File Name> . 2 . <Log Extension> prior.
This will occur all the way up to the value of 'maxLogs'.

28 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

Web Services
SugarCRM provides Web Services API’s via the NuSOAP PHP implementation of the SOAP protocol.
SOAP stands for "Simple Object Access Protocol." It is used for making Remote Procedure Calls through
the HTTP protocol by relaying messages in XML.

The SugarSoap API’s are built using the NuSOAP library and included in the Sugar Community Edition,
Sugar Professional Edition and Sugar Enterprise Edition. You can view the SugarSoap API’s at:

http://www.example.com/sugar/soap.php

The SugarSoap WSDL (Web Services Description Language) is located at:

http://www.example.com/sugar/soap.php?wsdl

Thanks to a myriad of toolkits available, it is easy to make effective use of SOAP Web Services from a
variety of programming languages, in particular with Sugar and its wide array of SOAP-based services
that it offers.

For these exercises, we will use PHP in conjunction with the NuSOAP Toolkit. You could of course
connect to SugarCRM via SOAP and write your application code in Java, C++ or a variety of other
SOAP-enabled programming languages.

Note: If the Sugar config.php variables site_url is wrong, SugarSoap will not work. Be sure to verify this
value before continuing.

Test Connection
If you would like to make sure you can connect to the SugarSoap API’S, use this test call. This call
will echo whatever you send in.

• Call: test

• Arguments:

o string:string – this is a string that you want to be echoed back to you

• Results:

o string:string – this is the string that was sent as an argument.

SugarSoap Login
First you will need to login to the SugarCRM system through the SOAP interface.

• Call: login

• Arguments:

o complex-type:user_auth – contains the user credentials used to log in.

Sugar Developer Guide 29


Chapter 1   SugarCRM Overview 

o string:application_name – this is a unique application name(example:


SugarCRM)

• Results:

o complex-type: set_entry_result - in this case the id of set_entry_result is the


SugarSoap API’s session_id.

• Note: This session id value is needed in all future SOAP calls. So you will want to store this
in a session or application level variable.

New complex types introduced in this section.

• user_auth is a struct containing three parameters:

o string:user_name – this is the SugarSoap user name

o string:password – this is an md5 of the SugarSoap user password

o string:version – this is the version of SOAP you are expecting(at this point use
1.0)

• set_entry_result is a struct containing two parameters.

o string:id - this is the id for the result

o complex-type:error (error_value) this is the error if any

• error_value is a struct containing three parameters:

o string:number - this is the error number. An error number of 0 indicates no errors


were encountered

o string:name – this is the error name

o string:description – this is the error description

Get the Current User ID


Sometimes it is useful to know the current user id. To get this information returned, call get_user_id.

• Call: get_user_id

• Arguments:

o string:session - this is the session_id retrieved during login that you should have
stored in either the application or the session scope

• Results:

30 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

o string:return – this is the user_id for the current SugarSoap user who logged in

Get a list of records for a module


This will return a list of entries (results) for a list view of a module. Team-based security restrictions
determine the resulting set of rows. It should also be noted that only the fields available in the
module’s list view is available through the get_entry_list call. Note that restrictions to field access
implemented via field-level ACLs (Professional and Enterprise Editions only) do not affect the fields
returned.

• Call: get_entry_list

• Arguments:

o string:session – this is the session_id

o string:module_name – this is the module you wish to get results for (e.g. 'Calls')

o string:query – this is the search query you wish to apply in retrieving the results
(e.g. “(calls.name LIKE 'doctor appointment%' AND calls.date_start =
CURDATE())” )

o string:order_by – this is what you would like to order by for the results (e.g. the
database column “calls.name”)

o complex-type:select_fields – these are the fields you want returned. SugarSoap


performance is better if you only retrieve the fields you need (e.g. name, description,
date_start, time_start).

o int:max_results – this is the maximum number of results you want returned if set
to 0 it will return the default SugarSoap API’s amount for ListViews.

• Results:

o complex-type:get_entry_list_result

New complex types introduced in this section include:

• select_fields is an array of strings (these are the names of fields for a given module)

• get_entry_list_result is an struct containing five parameters.

o int:result_count – the number of results returned

o int:next_offset – the next offset to use in a request

o complex-type:field_list – this is meta data of the fields returned

o complex-type:entry_list – this is the acctual result data

Sugar Developer Guide 31


Chapter 1   SugarCRM Overview 

o complex-type:error (error_value) any errors that occurred

• field_list is an array of complex-type:field

o field is a struct containing five parameters.

ƒ string:name – the db/sugar name for a field

ƒ string:type – the type of field (enum, text)

ƒ string:label – the translated label for the field

ƒ int:required – 1 for required 0 for not

• complex-type:name_value_list – these are additional options such as for enumeration it


would be the list of values for the enumeration.

o name_value_list is an array of complex-type:name_value

ƒ name_value is a struct containing two parameters. This is a name value pair.

• string:name – the name of the value (a.k.a key)

• string:value – the value for the name

• entry_list is an array of complex-type:entry_value

o entry_value is a struct containing three parameters:

ƒ string:id – the sugar id for the entry

ƒ string:module_name – the module this entry is from

ƒ complex-type:name_value_list – the field values for this entry

Get the values of a record


So we retrieved a list of results for a module but you might need more details on a single record
(entry) since get_entry_list is limited to what is available in the list view. You can get this
information by retrieving a single entry using get_entry.

• Call: get_entry

• Arguments:

o string:session – the session_id

o string:module_name – the module for the entry you want to retrieve

o string:id – the id of the entry you want to retrieve

32 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

o complex-type:select_fields - the fields you want to retrieve

• Results:

o complex-type:get_entry_result

get_entry_result is a new complex type introduced in this section. It is a struct containing three
parameters:

• complex-type:field_list – this is metadata of the fields returned

• complex-type:entry_list – this is the actual result data (in this case it will be an array of
size 1)

• complex-type:error (error_value) any errors that occurred

The reason for including entry_list in the same manner as get_entry_list_result is so that the
same function can create data structures for both calls.

Set the values for a record


You may want to now modify or even create a new record (entry). This is where set_entry comes
into place. Both modifying and creating a record are done from the same function call.

• Call: set_entry

• Arguments:

o string:session – the session_id

o string:module_name – the module for the entry you want to update/create

o complex-type:name_value_list - the fields you want to set

• Results:

o complex-type:get_entry_result

Pass in the primary id of a record in the name_value_list complex field if you have a field called id
otherwise to update a specific record. Otherwise if this field is empty, the system will create a new
entry.

Get the fields for a module


If you want to create a record (an entry) but don't have any fields to work with and there are no results
in the database, you can get a list of the available fields for a module. You use get_module_fields.

• Call: get_module_fields

• Arguments:

Sugar Developer Guide 33


Chapter 1   SugarCRM Overview 

o string:session – the session_id

o string:module_name – the module that you want a list of fields for

• Results:

o complex-type: module_fields – these are the fields to use

module_fields is a new complex type introduced in this section. It is a struct containing three
parameters:

• string:module_name – the module name for the fields

• complex-type:module_fields - (field_list) – these are the fields

• complex-type:error (error_value) - any errors that occurred

Logout
You need to clean up your session after you’re done.

• Call: logout

• Arguments:

o string:session – the session_id

• Results:

o complex-type:error (error_value) – any errors (not logged in?)

SugarSoap Examples
Every Sugar installation comes with a series of SugarSoap examples located in the examples/
directory of the application installation. There you will find several examples that go beyond those
outlined in this section.

Logging in via SOAP and getting a Sugar user's GUID


<?php
require_once('nusoap/nusoap.php');

$client = new soapclient('http://www.example.com/sugar/soap.php?wsdl',true);

$auth_array = array(
'user_auth' => array(
'user_name' => 'bob',
'password' => md5('mysecretpassword'),
)
);

$login_results = $client->call('login',$auth_array);

$session_id = $login_results['id'];

34 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

$user_guid = $client->call('get_user_id',$session_id);

printf("\n".$auth_array['user_auth']['user_name'].' has a GUID of ' . $user_guid .


"\n\n");
?>

Now let’s step this example line by line. Including the NuSOAP code sets up the soapclient
object.

require_once('nusoap/nusoap.php');

Instantiate the object with two parameters, the Sugar instances WSDL location and a flag that you
are passing in a WSDL.

$client = new soapclient('http://www.example.com/sugar/soap.php?wsdl',true);

Set up a data structure with the data needed to login.

$auth_array = array(
'user_auth' => array(
'user_name' => 'bob',
'password' => md5('mysecretpassword'),
);

We know the previous is needed because of the following WSDL snippets (from
http://www.example.com/sugar/soap.php?wsdl):

<message name="loginRequest">
<part name="user_auth" type="tns:user_auth"/>
<part name="application_name" type="xsd:string"/>
</message>

---and---

<xsd:complexType name="user_auth">
<xsd:all>
<xsd:element name="user_name" type="xsd:string"/>
<xsd:element name="password" type="xsd:string"/>
<xsd:element name="version" type="xsd:string"/>
</xsd:all>
</xsd:complexType>

Here is where we actually send the data. We are calling the 'login' SOAP method

$login_results = $client->call('login',$auth_array);

Now we grab a session id number

$session_id = $login_results['id'];

We know that we should look in 'id' because of the following WSDL snippet:

<message name="loginResponse">

Sugar Developer Guide 35


Chapter 1   SugarCRM Overview 

<part name="return" type="tns:set_entry_result"/>


</message>

---and---

<xsd:complexType name="set_entry_result">
<xsd:all>
<xsd:element name="id" type="xsd:string"/>
<xsd:element name="error" type="tns:error_value"/>
</xsd:all>
</xsd:complexType>
Now that we have a session ID, we can call another SOAP function, get_user_id:

$user_guid = $client->call('get_user_id',$session_id);
And print out some meaningful output with our findings:

printf("\n".$auth_array['user_auth']['user_name'].' has a GUID of ' . $user_guid .


"\n\n");

Inserting a Lead via SOAP calls using PHP


This example includes the PHP code necessary to log into the Sugar installation and insert a new
Lead record.

<?php
define('sugarEntry', TRUE);
//Use the NuSOAP files
require_once('nusoap/nusoap.php');

// change the URL here to point to your Sugar installation


$soapclient = new nusoapclient('http://www.example.com/sugar/soap.php?wsdl',true);

// change the user credentials below to be a valid user id and password for the Sugar
// installation defined above
$user_auth = array(
'user_auth' => array(
'user_name' => 'bob',
'password' => md5('mysecretpassword'),
'version' => '0.1'
),
'application_name' => 'soapleadcapture');

$result_array = $soapclient->call('login',$user_auth);

$session_id = $result_array['id'];

$user_guid = $soapclient->call('get_user_id',$session_id);

// Up until now, we have not introduced anything new


// The following lines will use the set_entry SOAP call to add
// a Lead from a mixture of POST variables and hard coded
// values, then assign to the authenticated Sugar user...
$set_entry_params = array(
'session' => $session_id,
'module_name' => 'Leads',

36 Sugar Developer Guide


Chapter 1   SugarCRM Overview 

'name_value_list'=>array(
array('name'=>'first_name','value'=>$_POST['first_name']),
array('name'=>'last_name','value'=>$_POST['last_name']),
array('name'=>'status', 'value'=>'New'),
array('name'=>'phone_work', 'value'=>$_POST['phone']),
array('name'=>'phone_fax', 'value'=>$_POST['fax']),

array('name'=>'account_name','value'=>$_POST['companyname']),
array('name'=>'lead_source','value'=>'Web Site'),
array('name'=>'description','value'=>$_POST['prod_desc']),
array('name'=>'assigned_user_id', 'value'=>$user_guid)));

$result = $soapclient->call('set_entry',$set_entry_params);

// this redirects to a page specified in the previous page...


header("Location: " . $_POST['redirect']);

?>

Note: it is also possible to create a NuSOAP client as follows without requiring the WSDL:

$ soapclient = new nusoapclient('http://www.example.com/sugar/soap.php’,false);

This actually speeds up processing since downloading the WSDL before invoking the method is
time intensive.

Sugar Developer Guide 37


Chapter 3 Module Framework

Overview
A Sugar Module consists of the following:

• A Vardefs file that specifies the Sugar metadata for the database table, fields, data types, and
relationships.

• A SugarBean file. SugarBean, the base class for all business objects in Sugar, implements the
functionality to create, retrieve, update, and delete objects in Sugar. Each module implements
this base class with additional properties and methods specific to that module.

• Metadata files that define the contents and layout of the Sugar screens.

o ListView: lists existing records in the module.

o DetailView: displays record details.

o EditView: allows user to edit the record.

o SubPanels: display the module's relationship with other Sugar modules.

o Popups: display list of records to link to another record.

User Interface Framework


Model-View-Controller (MVC) Overview
A model-view-controller, or MVC, is a design philosophy that creates a distinct separation between
business-logic and display logic.

• Model - This is the data object built by the business/application logic needed to present at the
user interface. For SugarCRM it is represented by the SugarBean and all subclasses of the
SugarBean.

• View - This is the display layer which is responsible for rendering data from the Model to the
end user.

• Controller - This is the layer that handles user events such as "Save" and determines what
business logic actions to take to build model, and what view to load to render the data to the
end user.

For more details on the MVC software design pattern, see the Wikipedia definition.

Sugar Developer Guide 38


Chapter 4   Module Framework 

SugarCRM MVC Implementation


The following is a sequence diagram that highlights some of the main components involved within
the SugarCRM MVC framework.

Model
The Sugar Model is represented by the SugarBean and any subclass of the SugarBean. Many of
the common Sugar modules also use the SugarObjects class described below.

Sugar Object Templates


Sugar Objects extend the concept of subclassing a step further and allows you to subclass
the vardefs. This includes inheriting of fields, relationships, indexes, and language files,
but unlike subclassing you are not limited to a single inheritance. If there were a Sugar
Object for fields used across every module such as id, deleted, or date_modified, you could
have your module inherit from both Basic Sugar Object and the Person Sugar Object.

Now let's say that the Basic type has a field 'name' with length 10 and Company has a field
'name' with length 20. If you inherit from Basic first then Company your field will be of
length 20. Now let's say you have defined a field 'name' in your module that is of length 60.
Your module will always override any values provided by Sugar Objects.

There are six types of Sugar Object Templates:

• Basic (contains the basic fields all Sugar modules require)

39     Sugar Developer Guide 
Chapter 4   Module Framework 

• Person (used by the Contacts, Prospects and Leads modules)

• Issue (used by the Bugs, Cases modules)

• Company (used by the Accounts module)

• File (based on Documents)

• Sale (based on Opportunities)

We can take this a step further and add assignable to the mix. An assignable module would
be one that can be assigned to users. Although this isn't used by every module, many
modules do let you assign records to users. SugarObject interfaces allow us to add
assignable to modules we wish to let users assign records.

SugarObject interfaces and SugarObject templates are very similar to one another, but the
main distinction is that templates have a base class you can subclass while interfaces do
not. If you look into the file structure you will notice that templates include many
additional files including a full metadata directory. This is currently used primarily for
Module Builder.

File Structure
• include/SugarObjects/interfaces
• include/SugarObjects/templates

Implementation
There are two things you need to do to take advantage of SugarObjects:
1) Your class needs to subclass the SugarObject class you wish to extend.
class MyClass extends Person{
function MyClass(){
parent::Person();
}
}
2) In your vardefs.php file add the following to the end:

VardefManager::createVardef('Contacts','Contact', array('default',
'assignable','team_security', 'person'));

This tells the VardefManager to create a cache of the Contacts vardefs with the
addition of all the default fields, assignable fields, team security fields (Sugar
Professional and Enterprise only), and all fields from the person class.

Performance Considerations
VardefManager caches the generated vardefs into a single file which will be the file loaded
at run time. Only if that file is not found will it load the vardefs.php file located in your
modules directory. The language files also do a similar thing. This caching also includes
data for custom fields and any vardef or language extensions that are dropped into the
custom/ext framework.

40 Sugar Developer Guide


Chapter 4   Module Framework 

Cache Files
• cache/modules/<mymodule>/<object_name>vardefs.php
• cache/modules/<mymodule>/langues/en_us.lang.php
Controller
Version 5.0 introduced a cascading controller concept to increase developer granularity over
customizations and to provide additional upgrade-safe capabilities. The main controller, called
SugarController, addresses the basic actions of a module from Edit and DetailViews to saving a
record. Each module can override this SugarController by adding a controller.php file into its
directory. This file extends the SugarController and the naming convention for the class is:

<ModuleName>Controller

Inside the controller you define an action method. The naming convention for the method is:

action_<action_name>

There are more fine grained control mechanisms a developer can use to override the controller
processing. For example if a developer wanted to create a new save action there are 3 places
where they could possibly override.

• action_save - this would be the broadest specification and would give the user full
control over the save process.

• pre_save - a user could override the population of parameters from the form

• post_save - this is where the view is being setup. At this point the developer could set a
redirect url, do some post save processing, or set a different view

Upgrade-Safe Implementation
You can also add a custom Controller that should extend the modules Controller if such
controller already exists. For example, if you want to extend the controller for a module
that comes with SugarCRM release 5.0, you should check if that module already has a
module-specific controller that came with the product. If so, you extend from that
controller class otherwise you extend from SugarController class. In both case, you should
place the custom controller class file in custom/modules/<MyModule>/Controller.php
instead of the module directory. Doing so makes your customization upgrade-safe.

File Structure
• include/MVC/Controller/SugarController.php
• include/MVC/Controller/ControllerFactory.php
• modules/<MyModule>/Controller.php
• custom/modules/<MyModule>/controller.php

Implementation
class UsersController extends SugarController{
function action_SetTimeZone(){

41     Sugar Developer Guide 
Chapter 4   Module Framework 

//Save TimeZone code in here


...
}
}

Mapping actions to files


You can choose not to provide a custom action method as defined above, and instead
specify your mappings of actions to files in $action_file_map. Take a look at
include/MVC/Controller/action_file_map.php as an example:

$action_file_map['subpanelviewer'] = 'include/SubPanel/SubPanelViewer.php';
$action_file_map['save2'] = 'include/generic/Save2.php';
$action_file_map['deleterelationship'] = 'include/generic/DeleteRelationship.php';
$action_file_map['import'] = 'modules/Import/index.php';

Here the developer has the opportunity to map an action to a file. For example Sugar uses a
generic SubPanel file for handling subpanel actions. You can see above that there is an
entry mapping the action ‘subpanelviewer' to include/SubPanel/SubPanelViewer.php.

The base SugarController class loads the action mappings in the following path sequence:

• include/MVC/Controller

• modules/<Module-Name>

• custom/modules/<Module-Name>

• custom/include/MVC/Controller

Each one loads and overrides the previous definition if in conflict. You can drop a new
action_file_map in the later path sequence that extends or overrides the mappings defined
in the previous one.

Upgrade-Safe Implementation
If you want to add custom action_file_map.php to an existing module that came with the
SugarCRM release, you should place the file at custom/modules/<Module-
Name>/action_file_map.php

File Structure
• include/MVC/Controller/action_file_map.php
• modules/<Module-Name>/action_file_map.php
• custom/modules/<Module-Name>/action_file_map.php

Implementation
$action_file_map['soapRetrieve'] = 'custom/SoapRetrieve/soap.php';

Classic Support (Not Recommended)


Classic support allows you to have files that represent actions within your module in a
manner similar to SugarCRM 4.5.1 and prior. Essentially you can just drop in a PHP file

42 Sugar Developer Guide


Chapter 4   Module Framework 

into your module and have that be handled as an action. This is not the recommended, but
is considered okay for backwards compatibility. It is a better practice to take advantage of
the action_<myaction> structure.

File Structure
• modules/<MyModule>/<MyAction>.php

Controller Flow Overview


For example if a request comes in for DetailView this is how the controller
will handle that request
• Start in index.php we load the SugarApplication instance
• SugarApplication instantiates SugarControllerFactory
• SugarControllerFactory loads the appropriate Controller
• Check for custom/modules/<MyModule>/Controller.php
o if not found, check for modules/<MyModule>/Controller.php
o if not found, load SugarController.php
• Call on the appropriate action
• Check for modules/<MyModule>/<MyAction>.php
o if not found, check for the method action_<MyAction> in the
controller.
o if not found, check for an action_file_mapping
o if not found, report error "Action is not defined"
View
Views are responsible for the display of information to the browser. Views are not just limited to
HTML data, you can have it send down JSON encoded data as part of the view or any other
structure you wish. As with the controllers there is a default class called SugarView which
implements a lot of the basic logic for views such as handling of headers and footers.

As a developer if you want to create a custom view you would place a view.<view_name>.php
file in a views/ subdirectory within the module. For example, for the DetailView you would
create a file name view.detail.php and place this within the views/ subdirectory within the
module. If a views subdirectory does not exist, you should create one.

In the file you should create a class named: <Module>View<ViewName>. For example, for a list
view within the Contacts module the class would be ContactsViewList. Note the first letter of
each word is uppercase and all other letters are lowercase.

You can extend the class from SugarView, the parent class of all views, or you can extend from
an existing view. For example extending from the out of the box list view can leverage a lot of the
logic that has already been done for displaying a list view.

Methods
There are two main methods to be overridden within a view:

43     Sugar Developer Guide 
Chapter 4   Module Framework 

• preDisplay() - This performs preprocessing within a view. When developing a


new view you should not worry about this method. It is only relevant for extending
existing views. For example, the include/MVC/View/views/view.edit.php file uses
this and allows developers who wishes to extend this view to leverage all of the
logic done in preDisplay() and either override the display() method completely
or within your own display() method call parent::display().

• display() - This performs the actual displaying of the data to the screen. This is
where the logic to display output to the screen should be placed.

Loading the View


The ViewFactory class tries to load the view for view in this sequence and will use the
first one it finds:

• custom/modules/<my_module>/views/view.<my_view>.php

• modules/<my_module>/views/view.<my_view>.php

• custom/include/MVC/View/view.<my_view>.php

• include/MVC/Views/view.<my_view>.php

Implementation
class ContactsViewList extends SugarView{
function ContactsViewList(){
parent::SugarView();
}

function display(){
echo 'This is my Contacts ListView';
}
}

File Structure
• include/MVC/Views/view.<myview>.php
• custom/include/MVC/Views/view.<myview>.php
• modules/<mymodule>/views/view.<myview>.php
• custom/modules/<mymodule>/views/view.<myview>.php
• include/MVC/Views/SugarView.php
Display Options for Views
The Sugar MVC provides developers with granular control how the screen looks when
their view is rendered. Each view can have a config file associated with it. So for the
example above, a developer would place a view.edit.config.php within the views/
subdirectory and when the EditView is rendered this config file will be picked up. When
loading the view ViewFactory class will merge the view config files from the following
possible locations with precedence order (high to low):

44 Sugar Developer Guide


Chapter 4   Module Framework 

• customs/modules/<module‐name>/views/view.<my_view>.config.php

• modules/<module‐name>/views/view.<my_view>.config.php

• custom/include/MVC/View/views/view.<my_view>.config.php

• include/MVC/View/views/view.<my_view>.config.php 

Implementation
The format of these files is as follows:

$view_config = array('actions' =>


array('popup' => array('show_header' => false,
'show_subpanels' => false,
'show_search' => false,
'show_footer' => false,
'show_JavaScript' => true,
),
),
'req_params' => array('to_pdf' =>
array('param_value' => true,
'config' => array('show_all' => false),
),
),
);

To illustrate this process, let’s take a look at how the ‘popup’ action is processed. In this
case the system will go to the actions entry within the view_config and determine the
proper configuration. Also if the request contains the parameter to_pdf and is set to be
true then it will automatically cause the show_all configuration parameter to be set
false, which means do not show any of the options.

Metadata Framework
Background
Metadata is defined as information about data. In SugarCRM, metadata refers to the framework of
using files to abstract the presentation and business logic found in the system. The metadata
framework is described in definition files that are processed using PHP. The processing usually
includes the use of Smarty templates for rendering the presentation and JavaScript libraries to handle
some business logic that affects conditional displays, input validation, etc.

Version 5.0 introduced a new metadata framework to manage the display of records in the system and
their respective edit or DetailViews. Metadata support for the search form has also been added in 5.0.

45     Sugar Developer Guide 
Chapter 4   Module Framework 

Application Metadata
All application modules are defined in the modules.php file. It contains several variables that define
which modules are active and usable in the application.

The file is located under the ‘<sugar root>/utils’ folder. It contains the $moduleList() array variable
which contains the reference to the array key to look up the string to be used to display the module in
the tabs at the top of the application, the coding standard is for the value to be in the plural of the
module name (i.e. Contacts, Accounts, Widgets, etc).

The $beanList() array stores a list of all active beans (modules) in the application. The $beanList
entries are stored in a ‘name’ => ‘value fashion with the ‘name’ value being in the plural and the
‘value’ being in the singular of the module name. The ‘value’ of a $beanList() entry is used to
lookup values in our next modules.php variable, the $beanFiles() array.

The $beanFiles variable is also stored in a ‘name’ => ‘value’ fashion. The ‘name’ is typically the
singular and a reference to the class name of the object which is looked up from the $beanList ‘value’
and the ‘value’ is a reference to the class file. From these three arrays you can include the class,
instantiate an instance, and execute module functionality.

For example:

global $moduleList,$beanList,$beanFiles;
$module_object = ‘Contacts’;
$class_name = $beanList[$module_object];
$class_file_path = $beanFiles[$class_name];
require_once($class_file_path);
$new_module_object = new $class_name();
$module_string_name = $moduleList[$module_object];

The remaining relevant variables in the modules.php file are the $modInvisList variable which
makes modules invisible in the regular UI (i.e., no tab appears for these modules), and the
$adminOnlyList which is an extra level of security for modules that are supposed to only be accessed
by administrators via the admin panel.

Module Metadata
The following table lists the metadata definition files found in the modules/[module]/metadata
directory and a brief description of their purpose within the system.

File Description

Used to render the popup information displayed when a user hovers the mouse
additionalDetails.php
cursor over a row in the list view.

46 Sugar Developer Guide


Chapter 4   Module Framework 

editviewdefs.php Used to render a record's EditView.

detailviewdefs.php Used to render a record's DetailView.

listviewdefs.php Used to render the list view display for a module.

Used to override the location of the metadata definition file to be used. The
metafiles.php EditView, DetailView, list view and popup code check for the presence of these
files.
popupdefs.php Used to render and handle the search form and list view in popups

searchdefs.php Used to render a module's basic and advanced search form displays

sidecreateviewdefs.php Used to render a module's quick create form shown in the side shortcut panel

subpaneldefs.php Used to render a module's subpanels shown when viewing a record's DetailView

SearchForm Metadata
The search form layout for each module is defined in the module’s metadata file searchdefs.php. A
sample of the Account's searchdefs.php appears as:

<?php
$searchdefs['Accounts'] = array(
'templateMeta' => array('maxColumns' => '3',
'widths' => array('label' => '10', 'field' => '30')),
'layout' => array(
'basic_search' => array(
'name',
'billing_address_city',
'phone_office',
array( 'name' => 'address_street',
'label' => 'LBL_BILLING_ADDRESS',
'type' => 'name',
'group'=> 'billing_address_street'
),
array( 'name'=>'current_user_only',
'label'=>'LBL_CURRENT_USER_FILTER',
'type'=>'bool'
),
),
'advanced_search' => array(
'name',
array( 'name' => 'address_street',
'label' =>'LBL_ANY_ADDRESS',
'type' => 'name'
),
array( 'name' => 'phone',
'label' =>'LBL_ANY_PHONE',
'type' => 'name'
),
'website',

47     Sugar Developer Guide 
Chapter 4   Module Framework 

array( 'name' => 'address_city',


'label' =>'LBL_CITY',
'type' => 'name'
),
array( 'name' => 'email',
'label' =>'LBL_ANY_EMAIL',
'type' => 'name'
),
'annual_revenue',
array( 'name' => 'address_state',
'label' =>'LBL_STATE',
'type' => 'name'
),
'employees',
array( 'name' => 'address_postalcode',
'label' =>'LBL_POSTAL_CODE',
'type' => 'name'
),
array('name' => 'billing_address_country',
'label' =>'LBL_COUNTRY',
'type' => 'name'
),
'ticker_symbol',
'sic_code',
'rating',
'ownership',
array( 'name' => 'assigned_user_id',
'type' => 'enum',
'label' => 'LBL_ASSIGNED_TO',
'function' => array('name' =>'get_user_array',
'params' => array(false) )
),
'account_type',
'industry',
),
),
);
?>
The contents of the searchdefs.php file contains an Array variable $searchDefs with one entry. The
key is the name of the module as defined in $moduleList array defined in include/modules.php. The
value of the $searchDefs array is another array that describes the search form layout and fields.

The 'templateMeta' key points to another array that controls the maximum number of columns in each
row of the search form ('maxColumns') as well as layout spacing attributes as defined by 'widths'. In
the above example, the generated search form files will allocate 10% of the width spacing to the
labels and 30% for each field respectively.

The 'layout' key points to another nested array which defines the fields to display in the basic and
advanced search form tabs. Each individual field definition maps to a SugarField widget. Please see
the SugarField widget section for an explanation about SugarField widgets and how they are rendered
for the search form, DetailView and EditView.

The searchdefs.php file is invoked from the MVC framework whenever a module's list view is
rendered (see include/MVC/View/views/view.list.php). Within view.list.php checks are made to see if
the module has defined a SearchForm.html file. If this file exists, the MVC will run in classic mode
and use the aforementioned 451 include/SearchForm/SearchForm.php file to process the search form.

48 Sugar Developer Guide


Chapter 4   Module Framework 

Otherwise, the new search form processing is invoked using include/SearchForm/SearchForm2.php


and the searchdefs.php file is scanned for first under the custom/modules/[module]/metadata directory
and then in modules/[module]/metadata.

The processing flow for the search form using the metadata subpaneldefs.php file is similar to that of
edit and DetailViews.

DetailView and EditView Metadata


Metadata files are PHP files that declare nested Array values that contain information about the view
(buttons, hidden values, field layouts, etc.). A visual diagram that represents how the Array values
declared in the Metadata file are nested is as follows:

The following diagram highlights the process of how the application determines which Metadata file
is to be used when rendering a request for a view.

49     Sugar Developer Guide 
Chapter 4   Module Framework 

The “Classic Mode” on the right hand side of the diagram represents the SugarCRM pre-5.x
rendering of a Detail/Editview. This section will focus on the MVC/Metadata mode.

When the view is first requested, the preDisplay method will attempt to find the correct Metadata file
to use. Typically, the Metadata file will exist in the [root level]/modules/[module]/metadata
directory, but in the event of edits to a layout through the Studio interface, a new Metadata file will be
created and placed in the [root level]/custom/modules/[module]/metadata directory. This is done so
that changes to layouts may be restored to their original state via Studio and also to allow changes
made to layouts to be upgrade-safe when new patches and upgrades are applied to the application.

The metafiles.php file that may be loaded allows for the loading of Metadata files that may have
alternate naming conventions or locations. An example of the metafiles.php contents can be found
for the Accounts module (though it is not used by default in the application).

$metafiles['Accounts'] = array(
'detailviewdefs' => 'modules/Accounts/metadata/detailviewdefs.php',
'editviewdefs' => 'modules/Accounts/metadata/editviewdefs.php',
'ListViewdefs' => 'modules/Accounts/metadata/ListViewdefs.php',
'searchdefs' => 'modules/Accounts/metadata/searchdefs.php',
'popupdefs' => 'modules/Accounts/metadata/popupdefs.php',
'searchfields' => 'modules/Accounts/metadata/SearchFields.php',

50 Sugar Developer Guide


Chapter 4   Module Framework 

);
After the Metadata file is loaded, the preDisplay method will also create an EditView object and
check to see if a Smarty template file needs to be built for the given Metadata file. The EditView
object does the bulk of the processing for a given Metadata file (creating the template, setting values,
setting field level ACL controls if applicable, etc.). Please see the EditView process diagram for
more detailed information about these steps.

After the preDisplay method is called in the view code, the display method is called and this results in
a call to the EditView object’s process method as well as the EditView object’s display method.

The EditView class is responsible for the bulk of the Metadata file processing and creating the
resulting display. The EditView class also checks to see if the resulting Smarty template is already
created and also applies the field level ACL controls for the SugarCRM Professional/Enterprise
editions.

The classes responsible for displaying the DetailViews and SearchForms also extend and use the
EditView class. The ViewEdit, ViewDetail and ViewSidequickcrate classes use the EditView class
to process and display its contents. Even the file that renders the quick create form display
(SubpanelQuickCreate.php) use the EditView class. DetailView (in DetailView2.php) and
SearchForm (in SearchForm2.php) extend the EditView class while SubpanelQuickCreate.php uses
an instance of the EditView class. The following diagram highlights these relationships.

51     Sugar Developer Guide 
Chapter 4   Module Framework 

EditView (EditView2.php)
-th : object
-tpl : string
-notes : string
-id : string
-metadataFile : string
-headerTpl : string
-footerTpl : string
-returnAction : string
ViewEdit (view.edit.php) «uses» -returnId : string
-ev : object -isDuplicate : bool
-type : string = edit -focus : object
-useForSubpanel : bool = false -module : string
-useModuleQuickCreateTemplate : bool = false -fieldDefs : object
-showTitle : bool = true -sectionPanels : object
-view : string «uses»
+preDisplay() : bool
-showDetailData : bool
+dislpay() : string
-showVCRControl : bool
«uses» -ss : object
ViewSidequickcreate (view.sidequickcreate. -offset : int
php) -populateBean : bool
-moduleTitleKey : string
+setup()
+preDisplay() : bool +createFocus()
+dislpay() : string +populateBean()
+requiredFirst() SubpanelQuickCreate.php
+render()
ViewDetail (view.detail.php) +process() +process():string
-type : string = detail +display() : string
-dv : object +callFunction() : string
+preDisplay() : bool +getValueFromRequest() : object
+dislpay() : string +showTitle() : string
+setModuleTitleKey()
«extends» «extends»

DetailView (DetailiView2.php) SearchForm (SearchForm2.php)


-view : string = DetailView -seed : object
+setup() -action : string = index
«uses» -searchdefs : object
-listViewDefs : object
-lv : object
-displayView : string = basic_search
-formData : object
-customFieldDefs : object
-tabs : object
-parsedView : string
-searchFields : object
-displaySavedSearch : bool = true
-view : string = SearchForm
-showAdvanced : bool = true
-showBasic : bool = true
-showCustom : bool = false
-nbTabs : int = 0
-showSavedSearchesOptions : bool = true
+setup()
+display() : string
+displaySavedSearch() : string
+displaySavedSearchSelect() : string
+_displayTabs() : string
+_build_field_defs()
+populateFromArray()
+generateSearchWhere() : object
+_createQuickSearchCode() : string

52 Sugar Developer Guide


Chapter 4   Module Framework 

The following diagram highlights the EditView class’ main responsibilities and their relationships
with other classes in the system. We will use the example of a DetailView request although the
sequence will be similar for other views that use the EditView class.

SugarController SugarView ViewDetail EditView TemplateHandler

process
preDisplay
new EditView()

EditView instance

setup

createFocus
display process
checkTemplate

no template exists?

render
yes

Set ACL on fields (PRO/ENT)

display
displayTemplate

build template (if not exists)


return view contents

return view contents

One thing to note is the EditView class’ interaction with the TemplateHandler class. The
TemplateHandler class is responsible for generating a Smarty template in the
cache/modules/<module> directory. For example, for the Accounts module, the TemplateHandler
will create the Smarty file cache/modules/Accounts/DetailView.tpl based on the Metadata file
definition and other supplementary information it is provided from the EditView class. The
TemplateHandler class actually uses Smarty itself to generate the resulting template that is placed in
the aforementioned cache directory.

Some of the modules that are available in the SugarCRM application also extend the ViewDetail
class. One example of this is the DetailView for the Projects module. As mentioned in the MVC
section, it is possible to extend the view classes by placing a file in the modules/<module>/views
directory. In this case, a view.detail.php file exists in the modules/Projects/views folder. This may
serve as a useful example in studying how to extend a view and apply additional field/layout settings
not provided by the EditView class.

The following is diagram shows in more detail the files involved with the DetialView example.

53     Sugar Developer Guide 
Chapter 4   Module Framework 

A high level processing summary of the components for DetailViews follows:

The MVC framework receives a request to process the DetaiView.php (A) action for a module. For
example, a record is selected from the list view shown on the browser with URL:

index.php?action=DetailView&module=Opportunities&record=46af9843-ccdf-f489-8833

At this point the new MVC framework checks to see if there is a DetailView.php (A2) file in the
modules/Opportunity directory that will override the default DetailView.php implementation. The
presence of a DetailView.php file will trigger the "classic" MVC view. If there isn't a DetailView.php
(A2) file in the directory, the MVC will also check if you have defined a custom view to handle the
DetailView rendering in MVC (i.e. check if there is a file
modules/Opportunity/views/view.detail.php). Please consult the documentation for the MVC
architecture for more notes about this. Finally, if neither the DetailView.php (A2) or view.detail.php
exist then the MVC will invoke include/DetailView/DetailView.php (A).

The MVC framework (see views.detail.php in include/MVC/View/views folder) creates an instance


of the generic DetailView (A)

// Call DetailView2 constructor


$dv = new DetailView2();

// Assign by reference the Sugar_Smarty object created from MVC


// We have to explicitly assign by reference to back support PHP 4.x
$dv->ss =& $this->ss;

// Call the setup function


$dv->setup($this->module, $this->bean, $metadataFile,
'include/DetailView/DetailView.tpl');

54 Sugar Developer Guide


Chapter 4   Module Framework 

// Process this view


$dv->process();

// Return contents to the buffer


echo $dv->display();

When the setup method is invoked, a TemplateHandler instance (D) will be created. A check is also
made to determine which detailviewdefs.php metadata file to use in creating the resulting DetailView.
The first check is made to see if a metadata file was passed in as a parameter. The second check is
made against the custom/studio/modules/[Module] directory to see if a metadata file exists. For the
final option, the DetailView constructor will use the module's default detailviewdefs.php metadata
file located under the modules/[Module]/metadata directory. If there is no detailviewdefs.php file in
the modules/[Module]/metadata directory, but a DetailView.html exists, then a "best guess" version is
created using the metadata parser file in include/SugarFields/Parsers/DetailViewMetaParser.php (not
shown in diagram).

The TemplateHandler also handles creating the quick search (Ajax code to do look ahead typing) as
well as generating the JavaScript validation rules for the module. Both the quick search and
JavaScript code should remain static based on the definitions of the current definition of the metadata
file. When fields are added/removed to the file via the Studio application, this template and the
resulting updated quick search and JavaScript code will be rebuilt.

It should be noted that the generic DetailView (A) defaults to using the generic DetailView.tpl smarty
template file (F). This may also be overridden via the constructor parameters. The generic DetailView
(A) constructor also retrieves the record according to the record id and populates the $focus bean
variable.

The process() method is invoked on the generic DetailView.php instance:

function process() {
//Format fields first
if($this->formatFields) {
$this->focus->format_all_fields();
}
parent::process();
}

This in turn, calls the EditView->process() method since DetailView extends from EditView. The
EditView->process() method will eventually call the EditView->render() method to calculate the
width spacing for the DetailView labels and values. The number of columns and the percentage of
width to allocate to each column may be defined in the metadata file. The actual values are rounded
as a total percentage of 100%. For example, given the templateMeta section’s maxColumns and
widths values:

'templateMeta' => array('maxColumns' => '2',


'widths' => array(
array('label' => '10', 'field' => '30'),
array('label' => '10', 'field' => '30')
),
),

55     Sugar Developer Guide 
Chapter 4   Module Framework 

We can see that the labels and fields are mapped as a 1-to-3 ratio. The sum of the widths only equals
a total of 80 (10 + 30 x 2) so the actual resulting values written to the Smarty template will be at a
percentage ratio of 12.5-to-37.5. The resulting fields defined in the metadata file will be rendered as
a table with the column widths as defined:

The actual metadata layout will allow for variable column lengths throughout the displayed table. For
example, the metadata portion defined as:

'panels' =>array (
'default' => array (
array (
'name',
array (
'name' => 'amount',
'label' => '{$MOD.LBL_AMOUNT} ({$CURRENCY})',
),
),
array (
'account_name',
),
array (
'',
'opportunity_type',
)
)
)

This specifies a default panel under the panels section with 3 rows. The first row has two fields (name
and amount). The amount field has some special formatting using the label override option. The second
row contains the account_name field and the third row contains the opportunity_type column.

56 Sugar Developer Guide


Chapter 4   Module Framework 

The second thing the process() method does is populate the $fieldDefs array variable with the
vardefs.php file (G) definition and the $focus bean's value. This is done by calling the toArray()
method on the $focus bean instance and combining these value with the field definition specificed in
the vardefs.php file (G).

The display() method is then invoked on the generic DetailView instance for the final step.
When the display() method is invoked, variables to the DetailView.tpl Smarty template are assigned
and the module's HTML code is sent to the output buffer.

Before HTML code is sent back, the TemplateHandler (D) first makes a check to see if an existing
DetailView template already exists in the cache respository (H). In this case, it will look for file
cache/modules/Opportunity/DetailView.tpl. The operation of creating the Smarty template is
expensive so this operation ensures that the work will not have to be redone. As a side note, edits
done to the DetailView or EditView via the Studio application will clear the cache file and force the
template to be rewritten so that the new changes are reflected.

If the cache file does not exist, the TemplateHandler (D) will create the template file and store it in
the cache directory. When the fetch() method is invoked on the Sugar_Smarty class (E) to create the
template, the DetailView.tpl file is parsed.

SugarField Widgets
SugarFields are the Objects that render the fields specified in the meta data (e.g., your *viewdefs.php
files). They can be found in include/SugarFields/Fields. In the directory
include/SugarFields/Fields/Base you will see the files for the base templates for rendering a field for
DetailView, EditView, ListView and Search Forms. As well as the base class called SugarFieldBase.

File Structure
• include/SugarFields/Fields/<fieldname>

• include/SugarFields/Fields/<fieldname>/DetailView.tpl

• modules/MyModule/vardefs.php

• modules/MyModule/metadata/<view>defs.php

57     Sugar Developer Guide 
Chapter 4   Module Framework 

Implementation
This section describes the SugarFields widgets that are found in the include/SugarFields/Fields
directory for release 5.0. Inside this folder you'll find a set of directories that encapsulate the
rendering of a field type (i.e. Boolean, Text, Enum etc.). There are also SugarFields directories
for grouped display values (e.g. Address, Datetime, Parent, and Relate). What we mean by
rendering is that there are user interface paradigms associated with a particular field type. For
example, a Boolean field type as defined in a module's vardef.php file can be displayed with a
checkbox indicated the boolean nature of the field value (on/off, yes/no, 0/1, etc.). Naturally there
are some displays in which the rendered user interface components are very specific to the
module's logic. In this case, it is likely that custom code was used in the metadata file definition.

SugarFields widgets are rendered from the metadata framework whenever the new 5.0 MVC
EditView, DetailView or list view actions are invoked for a particular module. Each of the
SugarFields will be discussed briefly.

Most SugarFields will contain a set of Smarty files to abstract rendering the field contents and
supporting HTML. Some SugarFields will also contain a subclass of SugarFieldBase to override
particular methods so as to control additional processing and routing of the corresponding Smarty
file to use. The subclass naming convention is defined as:

SugarField[Sugar Field Type]

where the first letter of the Sugar Field Type should be in uppercase. The contents should also be
placed in a corresponding .php file. For example, the contents of the enum type SugarField
(rendered as <select> in HTML) is defined in
include/SugarFields/Fields/Enum/SugarFieldEnum.php as:

class SugarFieldEnum extends SugarFieldBase {

function getDetailViewSmarty($parentFieldArray, $vardef, $displayParams,


$tabindex) {
if(!empty($vardef['function']['returns']) && $vardef['function']['returns']==
'html'){
$this->setup($parentFieldArray, $vardef, $displayParams);
return $this-
>fetch('include/SugarFields/Fields/Enum/DetailViewFunction.tpl');
}else{
return parent::getDetailViewSmarty($parentFieldArray, $vardef,
$displayParams, $tabindex);
}
}

function getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex)


{
if(!empty($vardef['function']['returns']) && $vardef['function']['returns']==
'html'){
$this->setup($parentFieldArray, $vardef, $displayParams);
return $this-
>fetch('include/SugarFields/Fields/Enum/EditViewFunction.tpl');
}else{
return parent::getEditViewSmarty($parentFieldArray, $vardef,
$displayParams, $tabindex);
}

58 Sugar Developer Guide


Chapter 4   Module Framework 

function getSearchViewSmarty($parentFieldArray, $vardef, $displayParams,


$tabindex) {
if(!empty($vardef['function']['returns']) && $vardef['function']['returns']==
'html'){
$this->setup($parentFieldArray, $vardef, $displayParams, $tabindex);
return $this-
>fetch('include/SugarFields/Fields/Enum/EditViewFunction.tpl');
}else{
$this->setup($parentFieldArray, $vardef, $displayParams, $tabindex);
return $this->fetch('include/SugarFields/Fields/Enum/SearchView.tpl');
}
}
}

Here we see how the enum type will use one of six Smarty template file depending on the view
(edit, detail or search) and whether or not the enum vardef definition has a 'function' attribute
defined to invoke a PHP function to render the contents of the field.

SugarFields Widgets Reference

Address
The Address field is responsible for rendering the various fields that together represent an
address value. By default SugarCRM renders address values in the United States format:

Street
City, State Zip
The Smarty template layout defined in DetailView.tpl reflects this. Should you wish to
customize the layout depending on the $current_language global variable, you may add
new files [$current_language].DetailView.tpl or [$current_language].EditView.tpl to the
Address directory that reflect the language locale's address formatting.

Within the metadata definition, the Address field can be rendered with the snippet:

array (
'name' => 'billing_address_street',
'hideLabel' => true,
'type' => 'address',
'displayParams'=>array('key'=>'billing', 'rows'=>2, 'cols'=>30,
'maxlength'=>150)
),

The vardefs.php entry to key field off of. Though not 100% ideal, we use the
name
street value

Boolean attribute to hide the label that is rendered by metadata framework.


We hide the billing_address_street label because the Address field already
hideLabel
comes with labels for the other fields (city, state). Also, if this is not set to
false, the layout will look awkward.

59     Sugar Developer Guide 
Chapter 4   Module Framework 

This is the field type override. billing_address_street is defined as a varchar


type in the vardefs.php file, but since we are interested in rendering an address
field, we are overriding this here

key - This is the prefix for the address fields. The address field assumes there
are [key]_address_street, [key]_address_state, [key]_address_city,
[key]_address_postalcode fields so this helps to distinguish in modules where
displayParams there are two or more addresses (e.g. 'billing' and 'shipping').

rows, cols, maxlength - This overrides the default HTML <textarea>


attributes for the street field component.

Note also the presence of file include/SugarFields/Fields/Address/SugarFieldAddress.js.


This file is responsible for handling the logic of copying address values (from billing to
shipping, primary to alternative, etc.). The JavaScript code makes assumptions using the
key value of the grouped fields.

To customize various address formats for different locales, you may provide a locale
specific implementation in the folder include/SugarFields/Fields/Address. There is a
default English implementation provided. Locale implementations are system wide specific
(you cannot render an address format for one user with an English locale and another
format for another with a Japanese locale). SugarCRM locale settings are system wide and
the SugarField implementation reflects this. To modify based on a user's locale preferences
will require some customizations, but is possible.

Base
The Base field is the default parent field. It simply renders the value as is for DetailViews
and an HTML text field <input type="text"> for EditViews. All SugarFields that have a
corresponding PHP file extend from SugarFieldBase.php.

Bool
The Bool field is responsible for rendering a checkbox to reflect the state of the value. In
release 5.0 all boolean fields are stored as integer values. The Bool field will render a
disabled checkbox for DetailViews. If the field value is "1" then the checkbox field will be
checked. There isno special parameter to pass into this field from the metadata definition.
As with any of the fields you have the option to override the label key string.

For example, in the metadata definition, the Boolean field do_not_call can be specified as:

'do_not_call'
or

array (
array('name'=>'do_not_call',
'label'=>'LBL_DO_NOT_CALL' // Overrides label as defined in vardefs.php

60 Sugar Developer Guide


Chapter 4   Module Framework 

)
),

Datetime
The Datetime field is responsible for rendering an input text field along with an image to
invoke the popup calendar picker. The Datetime field is different from the Datetimecombo
field in that there is no option to select the time values of a datetime database field.

Within the metadata definition, the Datetime field can be rendered with the snippet:

'date_quote_expected_closed', // Assumes that date_quote_exected_closed is defined


// as a datetime field in vardefs.php file
or

array('name'=>'date_quote_expected_closed',
'displayParams'=>array('required'=>true, 'showFormats'=>true)
),

name Standard name definition when metadata definition is defined as an array

required (optional) - Marks the field as required and applies clients side
validation to ensure value is present when save operation is invoked from
EditView.
displayParams
showFormats (optional) - Displays the user's date display preference as
retrieved from the global $timedate variable's get_user_date_format()
method.

Datetimecombo
The Datetimecombo field is similar to the Datetime field with additional support to render
dropdown lists for the hours and minutes values as well as a checkbox to enable/disable the
entire field. New in Sugar5.x is the consolidation of the date portion (e.g. 12/25/2007) and
time portion (e.g. 23:45) of the database fields. For example, in the 4.5.x versions, the
Calls and Meetings module defined two separate vardefs.php entries for the date and time
portion. Now that these two fields are consolidated, care must be taken by the module
developer to handle input from three HTML field values within the module class code.
Take for instance the vardefs.php definition for the date_start field in the Calls module:

'date_start' => array (


'name' => 'date_start',
'vname' => 'LBL_DATE',
'type' => 'datetime',
'required' => true,
'comment' => 'Date in which call is schedule to (or did) start'
),

There is one database field, but when the Datetimecombo widget is rendered, it will
produce three HTML fields for display- a text box for the date portion and two dropdown

61     Sugar Developer Guide 
Chapter 4   Module Framework 

lists for the hours and minutes values. The Datetimecombo widget will render the hours
and menu dropdown portion in accordance to the user's $timedate preferences. An optional
AM/PM meridiem drop down is also displayed should the user have selected a 12 hour
base format (e.g. 11:00).

Within the metadata definition, the Datetimecombo field can be rendered with the snippet:

array('name'=>'date_start',
'type'=>'datetimecombo',
'displayParams'=>array('required' => true,
'updateCallback'=>'SugarWidgetScheduler.update_time();',
'showFormats' => true,
'showNoneCheckbox' => true),
'label'=>'LBL_DATE_TIME'),

name Standard name definition when metadata definition is defined as an array

metadata type override. By default, the field defaults to Datetime so we need


type
to override it here in the definition.

required (optional) - Marks the field as required and applies clients side
validation to ensure value is present when save operation is invoked from
EditView.

updateCallback (optional) - Defines custom JavaScript function to invoke


when the values in the field are changed (date, hours or minutes).
displayParams
showFormats (optional) - Displays the user's date display preference as
retrieved from the global $timedate variable's get_user_date_format()
method.

showNoneCheckbox (optional) - Displays a checkbox that when checked


will disable all three field values

label
Standard metadata label override just to highlight this exhaustive example
(optional)

Download
The File field renders a link that references the download.php file for the given
displayParam['id'] value when in DetailView mode.

Within the metadata definition, the Download field can be rendered with the snippet:

array (
'name' => 'filename',
'displayParams' => array('link'=>'filename', 'id'=>'document_revision_id')

62 Sugar Developer Guide


Chapter 4   Module Framework 

),

name Standard name definition when metadata definition is defined as an array

required (optional) - Marks the field as required and applies clients side
validation to ensure value is present when save operation is invoked from
EditView.

displayParams id (required for DetailView) - The field for which the id of the file will be
opened via the download link.

link (required for DetailView) - The field for which the hyperlink value is
displayed.

Enum
The Enum field renders an HTML <select> form element that allows for a single value to
be chosen. The size attribute of the <select> element is not defined so the element will
render as a dropdown display in the EditView.

This field accepts the optional function override behavior that is defined at the vardefs.php
file level. For example, in the Bugs module we have for the found_in_release field:

'found_in_release'=>
array(
'name'=>'found_in_release',
'type' => 'enum',
'function'=>'getReleaseDropDown',
'vname' => 'LBL_FOUND_IN_RELEASE',
'reportable'=>false,
'merge_filter' => 'enabled',
'comment' => 'The software or service release that manifested the bug',
'duplicate_merge' => 'disabled',
'audited' =>true,
),

The function override is not handled by the SugarFields library, but by the rendering code
in include/EditView/EditView2.php.

Within the metadata definition, the Download field can be rendered with the snippet:

array (
'name' => 'my_enum_field',
'type' => 'enum',
'displayParams' => array('javascript'=>'onchange="alert(\'hello world!\')";')
),

63     Sugar Developer Guide 
Chapter 4   Module Framework 

name Standard name definition when metadata definition is defined as an array

size (optional) – Controls the size of the field (affects SearchForm control on
the browser only). Defaults to value of 6 for SearchForm.

required (optional) - Marks the field as required and applies clients side
displayParams validation to ensure value is present when save operation is invoked from
EditView.

javascript (optional) - Custom JavaScript to embed within the <select> tag


element (see above example for onchange event implementation).

File
The File field renders a file upload field in EditView and a hyperlink to invoke
download.php in DetailView. Note that you will need to override the HTML form's
enctype attribute to be "multipart/form-data" when using this field and handle the upload of
the file contents in your code. This form enctype attribute should be set in the
editviewdefs.php file. For example, for the Document's module we have the form override:

$viewdefs['Documents']['EditView'] = array(
'templateMeta' => array('form' =>
array('enctype'=>'multipart/form-data', // <--- override the enctype
),
)

Within the metadata file, the File field can be rendered with the snippet:

array (
'name' => 'filename',
'displayParams' => array('link'=>'filename', 'id'=>'document_revision_id'),
),

name Standard name definition when metadata definition is defined as an array

required (optional) - Marks the field as required and applies clients side
validation to ensure value is present when save operation is invoked from
EditView.

id (required for detailviewdefs.php) - The record id that download.php will


displayParams use to retrieve file contents
link (required for detailviewdefs.php) - The text to display between the <a>
</> tags.

size (optional) - Affects EditView only. Override to set the display length
attribute of the input field.

64 Sugar Developer Guide


Chapter 4   Module Framework 

maxlength(optional) - Affects EditView only. Override to set the display


maxlength attribute of the input field (defaults to 255).

Html
The Html field is a simple field that renders read-only content after the content is run
through the from_html method of include/utils/db_utils.php to encode entity references to
their HTML characters (i.e. "&gt;" => ">"). The rendering of the Html field type should be
handled by the custom field logic within SugarCRM.

name Standard name definition when metadata definition is defined as an array.

displayParams none

Iframe
In the DetailView, the Iframe field creates an HTML <iframe> element where the src
attribute points to the given URL value supplied in the EditView. Alternativly, the URL
may be generated from the values of other fields, and the base URL in the vardefs. If this is
the case, the field is not editable in the EditView.

name Standard name definition when metadata definition is defined as an array.

displayParams None

Image
Similar to the Html field, the Image field is simply renders a <img> tag where the src
attribute points to the value of the field. Image fields are rendered for DetailViews only.

Within the metadata file, the Image field can be rendered with the snippet:

array (
'name' => 'my_image_value', // <-- The value of this is assumed to be some
// URL to an image file
'type' => 'image',
'displayParams'=>array('width'=>100, 'length'=>100,
'link'=>'http://www.cnn.com', 'border'=>0),
),

name Standard name definition when metadata definition is defined as

65     Sugar Developer Guide 
Chapter 4   Module Framework 

an array

link (optional) - Hyperlink for the image when clicked on.

width (optional) - Width of image for display.


displayParams
height (optional) - Height of image for display.

border (optional) - Border thickness of image for display

Link
The link field simply generates an <a> HTML tag with a hyperlink to the value of the field
for DetailViews. For EditViews, it provides the convenience of pre-filling the "http://"
value. Alternatively, the URL may be generated from the values of other fields, and the
base URL in the vardefs. If this is the case, the field is not editable in the EditView.

Within the metadata file, the Link field can be rendered with the snippet:

array (
'name' => 'my_image_value', // <-- The value of this is assumed to
// be some URL to an image file
'type' => 'link',
'displayParams'=>array('title'=>'LBL_MY_TITLE'),
),

name Standard name definition when metadata definition is defined as an array

required (optional) - Marks the field as required and applies clients side
validation to ensure value is present when save operation is invoked from
EditView.

title (optional for detailviewdefs.php only) - The <a> tag's title attribute for
displayParams browsers to display the link in their status area

size (optional) - Affects EditView only. Override to set the display length
attribute of the input field.

maxlength(optional) - Affects EditView only. Override to set the display


maxlength attribute of the input field (defaults to 255).

Multienum
The Multienum fields renders a bullet list of values for DetailViews and renders a <select>
form element for EditViews that allow multiple values to be chosen. Typically, the custom
field handling in SugarCRM will map multienum types created via Studio so you would

66 Sugar Developer Guide


Chapter 4   Module Framework 

not need to declare metadata code to specify the type override. Nevertheless, within the
metadata file, the Multienum field can be rendered with the snippet:

array (
'name' => 'my_multienum_field',
'type' => 'multienum',
'displayParams' => array('javascript'=>'onchange="alert(\'hello world!\')";')
),

name Standard name definition when metadata definition is defined as an array

size (optional) – Controls the size of the field (affects SearchForm control on
browser only). Defaults to value of 6 for SearchForm.

required (optional) - Marks the field as required and applies clients side
displayParams validation to ensure value is present when save operation is invoked from
EditView.

javascript (optional) - Custom JavaScript to embed within the <select> tag


element (see above example for onchange event implementation).

Parent
The parent field combines a blend of a dropdown for the parent module type and a text
field with code to allow quicksearch for quicksearch enabled modules (please see
include/SugarFields/Fields/Parent/EditView.tpl file contents and the JavaScript code there
for more info on quicksearch enabling). There are also buttons to invoke popups and a
button to clear the value. Because the parent field assumes proper relationships within the
SugarCRM modules it is not a field you can add via Studio nor a field you should attempt
to type override in the metadata files.

Password
The password field simply renders an input text field with the type attribute set to
"password" to hide user input values. It is available to EditViews only.

name Standard name definition when metadata definition is defined as an array

required (optional) - Marks the field as required and applies clients side
validation to ensure value is present when save operation is invoked from
displayParams EditView.
size (optional) - Override to set the display length attribute of the input field
(defaults to 30).

67     Sugar Developer Guide 
Chapter 4   Module Framework 

Phone
The phone field simply invokes the callto:// URL references that could trigger Skype or
other VOIP applications installed on the user's system. It is rendered for DetailViews only.

Radioenum
The Radioenum field renders a group of radio buttons. Radioenum fields are similar to the
enum field, but only one value can be selected from the group.

Readonly
The readonly field simply directs EditView calls to use the SugarField's DetailView
display. There are no Smarty .tpl files associated with this field.

Relate
The Relate field combines a blend of a text field with code to allow quicksearch. The
quicksearch code is generated for EditViews (see
include/TemplateHandler/TemplateHandler.php). There are also buttons to invoke popups
and a button to clear the value. For DetailViews, the Relate field creates a hyperlink that
will bring up a DetailView request for the field's value.

Within the metadata file, the Relate field can be rendered with the snippet:

array (
array('name'=>'account_name',
'type'=>'relate',
'displayParams'=>array('allowNewValue'=>true)
),
),

This will create a relate field that allows the user to input a value not found in the
quicksearch list.

name Standard name definition when metadata definition is defined as an array

required (optional) - Marks the field as required and applies clients side
validation to ensure value is present when save operation is invoked from
EditView.

readOnly (optional for editviewdefs.php file only) - Makes the text field input
area readonly so that you have to just use the popup selection.
displayParams
popupData - This field is generated for you by default. See
include/SugarFields/Fields/SugarFieldRelate.php for more information. You
should not need to override this setting.

allowNewValue (optional for editviewdefs.php file only) - This setting allows


the user to specify a value that is not found from the quicksearch list of

68 Sugar Developer Guide


Chapter 4   Module Framework 

results.

hideButtons (optional for editviewdefs.php SearchForm.php and


popupdefs.php) – Hides the Select and Clear buttons normally displayed next
to the editable Relate field.

Text
The Text field renders a <textarea> HTML form element for EditViews and dislpays the
field value with newline characters converted to HTML elements in DetailViews.

name Standard name definition when metadata definition is defined as an array

required (optional) - Marks the field as required and applies clients side
validation to ensure value is present when save operation is invoked from
EditView.

maxlength (optional for editviewdefs.php file only) - Sets the maximum


displayParams length of character input allowed in the <textarea> field.
rows (optional for editviewdefs.php file only) - Sets the number of rows in
the <textarea>field.

cols (optional for editviewdefs.php file only) - Sets the number of cols in the
<textarea> field.

Username
The Username field is a helper field that assumes a salutation, first_name and last_name
field exists for the vardefs of the module. It displays the three fields in the format:

[salutation] [first_name] [last_name]

Metadata Framework Summary


In summary, the new metadata framework simplifies the management of the detail and EditViews by
reducing the number of individual .tpl or .html files currently used in 4.X versions and prior. The
problem was that a change to a module's view required the editing of the module's .html or .tpl file
and with that, the extra checks against malformed html or smarty tags as well as proper field type
displays (select elements for enum fields, checkboxes for booleans, etc.). By moving to a metadata
driven framework, the fields that are rendered are tied directly to the module's vardefs.php file
definition (barring any customization).

69     Sugar Developer Guide 
Chapter 4   Module Framework 

Vardefs
Vardefs (Variable Definitions) are used to provide the Sugar application with information about
SugarBeans. They specify information on the individual fields, relationships between beans, and the
indexes for a given bean. Each module that contains a SugarBean file has a vardefs.php file located in it,
which specifies the fields for that SugarBean. For example, the Vardefs for the Contact bean is located in
sugarcrm/modules/Contacts/vardefs.php.

Vardef files create an array called "$dictionary", which contains several entries including tables, fields,
indices, and relationships.

Dictionary Array
• 'table' = The name of the database table (usually, the name of the module) for this bean that
contains the fields.

• 'audited' = Set to True if this module has auditing turned on

• 'fields' = A list of fields and their attributes (see below)

• 'indices' = A list of indexes that should be created in the database (see below)

• 'relationships' = A list of the relationships for this bean (see below)

• 'optimistic_locking' = True if this module should obey optimistic locking. Optimistic locking
uses the modified date to ensure that the bean you are working on has not been modified by
anybody else when you try and save. This prevents loss of data.

Fields Array
The fields array contains one array for each field in the SugarBean. At the top level of this array the
key is the name of the field, and the value is an array of attributes about that field.

The list of possible attributes are as follows:

• 'name' = The name of the field

• 'vname' = The language pack id for the label of this field

• 'type' = The type of the attribute

o 'relate' = Related Bean

o 'datetime' = A date and time

o 'bool' = A boolean value

o 'enum' = An enumeration (drop down list from the language pack)

o 'char' = A character array

70 Sugar Developer Guide


Chapter 4   Module Framework 

o 'assigned_user_name' = A linked user name

• 'varchar' = A variable sized string

• 'table' = The table this field comes from

• 'isnull' = Is this field allowed to be set to null?

• 'len' = The length of the field (number of characters if a string)

• 'options' = The name of the enumeration in the language pack for this field

• 'dbtype' = The database type of the field (if different than the type)

• 'reportable' = Should this field show up in the list of fields for the reporting module (if
applicable).

• 'required' = true if this field is a required field

• 'default' = The default value for this field

• 'massupdate' = false if you do not want this field to show up in the mass update section at the
bottom of the list views. Defaults to true.

• 'rname' = (for type relate only) The field from the related variable that has the text

• 'id_name' = (for type relate only) The field from the bean that stores the id for the related
Bean

• 'source' = 'nondb' if the field value does not come from the database. This can be used for
calculated values or values retrieved in some other way.

• 'sort_on' => The field to sort by if multiple fields are used.

• 'fields' => (for concatenated values only) An array containing the fields that are concatenated.

• 'db_concat_fields'=> (for concatenated values only) An array containing the fields to


concatenate in the DB.

The following example illustrates a standard ID field for a Bean.

'id' => array (


'name' => 'id',
'vname' => 'LBL_ID',
'type' => 'id',
'required'=>true,
),

Indices Array
This array contains a list of arrays that are used to create indexes in the database. The fields in this
array are:

71     Sugar Developer Guide 
Chapter 4   Module Framework 

o 'name' = The name of the index. This must be unique in most databases.

o 'type' = The type of the index (primary, unique, or index)

o 'fields' = The fields to index. This is an ordered array.

The following example is to create a primary index called 'userspk' on the 'id' column

array('name' =>'userspk', 'type' =>'primary', 'fields'=>array('id')),

Relationships Array
The relationships array is used to specify relationships between Beans. Like the Indices array entries,
it is a list of names with array values.

• 'lhs_module' = The module on the left hand side of the relationship

• 'lhs_table' = The table on the left hand side of the relationship

• 'lhs_key' = The primary key column of the left hand side of the relationship

• 'rhs_module' = The module on the right hand side of the relationship

• 'rhs_table' = The table on the right hand side of the relationship

• 'rhs_key' = The primary key column of the right hand side of the relationship

• 'relationship_type' = The type of relationship ('one-to-many' or 'many-to-many')

• ‘relationship_role_column’ = The type of relationship role

• 'relationship_role_column_value' = Defines the unique identifier for the relationship role

The following example creates a reporting relationship between a contact and the person that they
report to. The reports_to_id field is used to map to the id field in the contact of the person they report
to. This is a one-to-many relationship in that each person is only allowed to report to one person.
Each person is allowed to have an unlimited number of direct reports.

'contact_direct_reports' => array(


'lhs_module' => 'Contacts',
'lhs_table' => 'contacts',
'lhs_key' => 'id',
'rhs_module' => 'Contacts',
'rhs_table' => 'contacts',
'rhs_key' => 'reports_to_id',
'relationship_type' => 'one-to-many'),

Many-to-Many Relationships
In the ./metadata directory, all the many-to-many relationships are defined and included in the $dictionary
array. The files are stored in ./metadata/<relation_table_name>MetaData.php. Tables are generated

72 Sugar Developer Guide


Chapter 4   Module Framework 

based on these definitions. These files are included via the ./modules/TableDictionary.php. If you create
a custom many-to-many relationship, you will need to add the reference to your newly relationships by
adding the new reference in the file custom/application/Ext/TableDictionary/tabledictionary.php. You
may need to create this file if it does not exist. These changes will take affect after you clear the Sugar
Cache by running the “Quick Repair and Rebuild” option from the Admin Repair screen.

The following are the definitions for $dictionary[<relation_table>]. They are similar to the Vardefs.
If necessary use that page as a reference as well.

• <relation_table> - the index for this relationship in the $dictionary array

• table - the name of the table that is created in the database

• fields - array containing arrays for each column definition. The join table must have a field for the
primary key of each table to be linked, a primary key for the join table itself, a deleted field for
relationship unlinking, and a date_modifed field to track when the relationship changes.
Additional fields can be added to track the role played by the relationship,

• indices - the database indices. Note see the example for indices below for necessary values.

• relationships - definitions of the relationships between the two tables

o lhs_module - the left hand module. Should match $beanList index

o lhs_table - the left hand table name

o lhs_key - the key to use from the left table

o rhs_module - the right hand module. Should match $beanList index

o rhs_table - the right hand table name

o rhs_key - the key to use from the right table

o relationship_type - relationship type

o join_table - join table used to join items

o join_key_lhs - left table key. Should exist in table field definitions above

o join_key_rhs - right table key. Should exist in table field definitions above

Note that Relationship metadata and the Vardefs are the critical building blocks of the new ListViews. In
conjunction with [module]/metadata/ListViewdefs.php, these three elements generate your ListView.

For example, you may need to display data from another module or even just another table (not part of a
module). To do this, you will need to get all your queries in order () AND add the reference in
Vardefs.php. The new ListViews can ONLY display data registered in the Vardefs.

For example:

73     Sugar Developer Guide 
Chapter 4   Module Framework 

'store_name' => array ( 'name' => 'store_name',


'rname' => 'name',
'id_name' => 'id',
'vname' => 'LBL_STORE_NAME',
'type' => 'relate',
'link'=>'store_name',
'table' => 'jd_stores',
'join_name'=>'stores',
'isnull' => 'true',
'module' => 'Stores',
'dbType' => 'varchar',
'len' => 100,
'source'=>'non-db',
'unified_search' => false,
'massupdate' => false,
'comment' => 'The name of the store represented by the store_id field in
customer_service' ),

In this case, Stores is not a module, but jd_stores is a table. The joins with that table are handled in
fill_in_additional_detail_fields(), fill_in_additional_list_fields(), create_list_query(), and (depending on
your situation) create_new_list_query(). You need to get all these things straight, but you will still not get
your data on your ListView is you do not register it in Vardefs.

Subpanels
Subpanels are used in a given module’s DetailView to display relationships with other modules.
Examples include the Contacts subpanel “under” the Opportunities module DetailView, or the Tasks
subpanel for the Projects module.

The references below are the places in the code where subpanels are generated from. Running rebuild
relationships in the repair section in the admin panel is necessary after making changes to or creating
subpanels.

The module that contains the subpanel is where the vardefs array index is defined. There is an index
referring to the module that will appear as the subpanel of type 'link'.

One-to-Many Relationships
For Accounts, the reference necessary for the Cases subpanel is defined as follows in the
./modules/Accounts/vardefs.php

'cases' => array (


'name' => 'cases',
'type' => 'link',
'relationship' => 'account_cases', //relationship definition is below
'module'=>'Cases',
'bean_name'=>'aCase',
'source'=>'non-db',
'vname'=>'LBL_CASES',
),
For a one-to-many, the 'relationship' index defined above must also be in the vardefs.

'account_cases' => array(

74 Sugar Developer Guide


Chapter 4   Module Framework 

'lhs_module'=> 'Accounts',
'lhs_table'=> 'accounts',
'lhs_key' => 'id',
'rhs_module'=> 'Cases',
'rhs_table'=> 'cases',
'rhs_key' => 'account_id',
'relationship_type'=>'one-to-many'
),
Since this is a one-to-many, there is no need for a relationship table, which is only defined in the
./metadata directory.

Many-to-Many Relationships
For Accounts, the reference necessary for the Bugs subpanel is defined as follows in the
./modules/Accounts/vardefs.php

'bugs' => array (


'name' => 'bugs',
'type' => 'link',
'relationship' => 'accounts_bugs', //relationship table
'module'=>'Bugs',
'bean_name'=>'Bug',
'source'=>'non-db',
'vname'=>'LBL_BUGS',
),
Since this is many to many and there already exists a relationship table, there is no need to define the
relationship in the vardefs. However, the relationship metadata must be defined as shown below.

Relationship Metadata
If you have a many-to-many relationship, a table must exist for the relationship. If this is a new
relationship then you must add the details of the relationship file (accounts_bugsMetaData.php in this
example) to TableDictionary.php in the /modules directory. You must then run Repair Database to
create the new relationships table (accounts_bugs in the example below). To remain upgrade-safe you
must put your custom changes into /custom/application/ext/tabledictionary/tabledictionary.ext.php.

In the ./metadata directory, the relationship must exist and included in the $dictionary array. To keep
consistent with the above accounts_bugs example, here is the content of the
accounts_bugsMetaData.php

$dictionary['accounts_bugs'] = array(
'table' => 'accounts_bugs', //the table that is created in the database
'fields' => array (
array('name' =>'id', 'type' =>'varchar', 'len'=>'36',), // the unique id for the
relationship
array('name' =>'account_id', 'type' =>'varchar', 'len'=>'36'), // the id for the
account
array('name' =>'bug_id', 'type' =>'varchar', 'len'=>'36'), // the id for the bug
array('name' => 'date_modified','type' => 'datetime'), // necessary
array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'required'=>true,
'default'=>'0') // necessary
),
// the indices are necessary for indexing and performance
'indices' => array (
array('name' =>'accounts_bugspk', 'type' =>'primary', 'fields'=>array('id')),

75     Sugar Developer Guide 
Chapter 4   Module Framework 

array('name' =>'idx_acc_bug_acc', 'type' =>'index',


'fields'=>array('account_id')),
array('name' =>'idx_acc_bug_bug', 'type' =>'index', 'fields'=>array('bug_id')),
array('name' => 'idx_account_bug', 'type'=>'alternate_key',
'fields'=>array('account_id','bug_id'))
),
'relationships' => array(
'accounts_bugs' => array(
'lhs_module'=> 'Accounts', // the left hand module - should match $beanList
index
'lhs_table'=> 'accounts', // the left hand table name
'lhs_key' => 'id', // the key to use from the left table
'rhs_module'=> 'Bugs', // the right hand module - should match $beanList index
'rhs_table'=> 'bugs', // the right hand table name
'rhs_key' => 'id', // the key to use from the right table
'relationship_type'=>'many-to-many', // relationship type
'join_table'=> 'accounts_bugs', // join table - table used to join items
'join_key_lhs'=>'account_id', // left table key - should exist in table field
definitions above
'join_key_rhs'=>'bug_id' // right table key - should exist in table field
definitions above
)
)
)

Layout Defs
This is the file that contains the related modules to create subpanels for. It is stored in the
$layout_defs array $layout_defs[<module>]['subpanel_setup'][<related_module>].

This example is from the account metadata/subpaneldefs.php

'contacts' => array(


'order' => 30,// the order in which this subpanel is displayed with other subpanels
'module' => 'Contacts',
'subpanel_name' => 'default', // in this case, it will use
./modules/Contacts/subpanels/default.php
'get_subpanel_data' => 'contacts',
'add_subpanel_data' => 'contact_id',
'title_key' => 'LBL_CONTACTS_SUBPANEL_TITLE',
'top_buttons' => array( // this array defines the top buttons
array('widget_class' => 'SubPanelTopCreateAccountNameButton'),
array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect')
),
),
In the language file for the module containing the subpanel, the following values need to be added.

• The reference used in 'title_key' as shown above

• In the example, it would be $mod_strings['LBL_CONTACTS_SUBPANEL_TITLE'] =


'Contacts';

• The reference used in 'vname' as shown in the vardefs section

In the example, it would be $mod_strings['LBL_CASES'] = 'Cases';

76 Sugar Developer Guide


Chapter 4   Module Framework 

Shortcuts
Menu shortcuts for modules are easy to implement.. There is a ./modules/MODULE_NAME/Menu.php in
all applicable modules. Shorcuts are generated via:

$module_menu[]=Array("URLLINK", "SHORTCUTTEXT", "IMAGEFILENAME");


• URLLINK - the link that the shortcut points to

• SHORTCUTTEXT - the text that displays in the menu

• IMAGEFILENAME - the filename in the themes image directory


Note: A .gif extension is required for the image file and assumed in the definition.

Example from ./modules/Cases/Menu.php

$module_menu[] =
Array("index.php?module=Cases&action=index&return_module=Cases&return_action=DetailVie
w", $mod_strings['LNK_CASE_LIST'],"Cases")

77     Sugar Developer Guide 
Chapter 4 Customizing Sugar
Customizing SugarCRM enables you to tailor your Sugar installation to your business needs. This chapter
explains the different ways to customize SugarCRM.

Introduction
The extension framework in Sugar was created to help implement the customization of existing modules
or create entirely new modules. Through the various extensions available you can extend most of the
functionality of Sugar in an upgrade-safe manner. The Module Builder tool and Studio tool available in
the Admin screen allows you to make the most common customizations outlined below. You can then
further extend your system by adding upgrade-safe custom code.

Most common customizations are done with the suite of developer tools provided in the Sugar Admin
screen. Those tools include:
• Module Builder - Build new modules to expand the functionality of SugarCRM
• Module Loader - Add or remove Sugar modules, themes, and language packs
• Studio - Edit Dropdowns, Custom Fields, Layouts and Labels
• Dropdown Editor - Add, delete, or change the dropdown lists in the application
• Portal - Add tabs which can display any Web site within the application
• Configure Tabs - Choose which module tabs are displayed within the application
• Rename Tabs - Change the label of the module tabs
• Configure Group Tabs - Create and edit groupings of tabs
For further information on how to use these tools, please refer to the “Sugar Installation and
Administration Guide”. This guide will go into more detail on how to use the Module Builder and the
Module Loader as well as extend the Sugar system at the code-level beyond what these tools provide.

Tips & Pitfalls


Making upgrade-safe customizations
Because SugarCRM is an open source application, you have access to all of the source code.
Keep in mind that just because you can change the code doesn’t mean that you should. Any code
customizations you make to the core files that ship with the SugarCRM distribution will need to
be merged forward or re-factored manually when you upgrade to the next patch or major release.

However, any changes you make using the developer tools provided in the Admin screen
(Module Builder, Studio, etc.) are upgrade-safe. Also, any code changes you make in the custom/
directory are also upgrade-safe.

Sugar Developer Guide 78


Chapter 5   Customizing Sugar 

Installing Third-Party Modules


Be aware that not all third-party modules you install in your Sugar system (such as modules
found on SugarForge.org) have been designed to interoperate error-free with other modules and
may not be upgrade-safe. Code changes made by a third-party developer and distributed in a
module could potentially modify core files which would require special attention during an
upgrade. Also, two different modules could conflict with one another in the changes they make
to your system.

Naming Your Custom Modules


If you create a new module or Sugar Dashlet and don’t use the Module Builder tool to do this, be
sure to name your new directories uniquely. This will prevent conflicts with future modules
added by the Sugar team. For instance, a best practice would be to add a unique prefix to your
new module’s directory name such as “zz_Brokers” for a new Brokers module.

Be Familiar with Object Oriented Programming


Much of extending the Sugar functionality is based around extending and overriding the
SugarCRM base classes. Developers need to be familiar with the basics of object-oriented
programming and are encouraged to only extend the SugarCRM base classes to the minimum
extent necessary.

Use Developer Mode when Customizing the User Interface


When developing in SugarCRM, it is suggested that you turn on Developer Mode (Admin-
>System Settings->Advanced->Developer Mode) which causes the system to ignore the cached
metadata files. This is especially helpful when you are altering templates, metadata or language
files directly. When using Module Builder or Studio, the system will automatically refresh the
file cache. Be sure to turn Developer Mode off when you have completed your customizations as
Developer Mode does degrade system performance.

The Custom Directory


The SugarCRM system contains a top level directory called the “custom” directory. This directory
contains metadata files and custom code that override and extend the base Sugar functionality. Some of
the files in this directory are auto-generated by the Module Builder, Studio and Workflow (Sugar
Professional and Sugar Enterprise only) tools and other files can be added or modified directly by a
developer. Before discussing how a developer can use the Sugar tools to modify the application, an
understanding of the “custom” directory is useful.

Vardefs
Vardefs define field attributes for a given module. Existing vardefs can be modified and new vardefs
can be created by modifying Vardefs files in the custom directory.

Master Directories
Files in these directories can be edited and new files can be added to these directories.

79     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

/custom/Extension/modules/<MODULE_NAME>/Ext/Vardefs/

Production Directories
Files in these directories are auto-generated by the system.

/custom/modules/<MODULE_NAME>/Ext/Vardefs/vardefs.ext.php

Description
Vardefs files either replace entirely or add to the field definitions that are available to a module.
In the Master Directories you can have many files like:

• /custom/Extension/modules/Calls/Ext/Vardefs/New_vardefs.php

• /custom/Extension/modules/Calls/Ext/Vardefs/Updated_Vardefs.php

During the repair function (Admin->Repair->Quick Repair and Rebuild), all of these files will be
merged together into the production directory and they become the file:

/custom/modules/Calls/Ext/Vardefs/vardefs.ext.php

For example, a vardefs extension file for the Calls module could contain the following:

/custom/Extension/modules/Calls/ext/Vardefs/Import_Vardefs.php

<?php
$dictionary['Call']['fields']['parent_type']['vname'] = 'LBL_PARENT_TYPE';
$dictionary['Call']['fields']['parent_id']['vname'] = 'LBL_PARENT_ID';}
$dictionary['Call']['fields']['deleted']['importable'] = false;

$dictionary['Call'] = array('fields' => array (


'related_id' => array (
'name' => 'related_id',
'vname' => 'LBL_RELATED_ID',
'type' => 'id',
'required' => false,
'reportable' => false,
'audited' => true,
'comment' => 'ID of a related record of this call',
);
?>
This would change the values for the “vname” of parent_type and parent_id, it would add an
“importable” value to the deleted field and set it to false and then add a whole new field called
related_id to the calls field list.

Languages
It is possible to override display string values for a given language and create entirely new strings
used by new custom fields.

Master Directories
Files in these directories can be edited and new files can be added to these directories.

• /custom/include/language/ (for $app_strings or $app_list_strings)

80    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

• /custom/Extension/application/Ext/Include/

• /custom/Extension/modules/<MODULE_NAME>/Ext/Language/ (for $mod_strings only)

Production Directories
Files in these directories are auto-generated by the system.

• /custom/include/language/<LANGUAGE_TAG>.lang.ext.php

• /custom/modules/<MODULE_NAME>/Ext/Languages/<LANGUAGE_TAG>.lang.ext.ph
p

Description
Language files either replace entirely or add to the translated language items available to a
module. In the Master Directories you can have many files like:

• /custom/Extension/modules/Leads/Ext/Language/en_us.Custom_strings.php

• /custom/Extension/modules/Leads/Ext/Language/en_us.Custom_Languages.php

During the repair function (Admin->Repair->Quick Repair and Rebuild), all of these files will be
merged together into the production directory and they become the file:

/custom/modules/Leads/Ext/Language/en_us.lang.ext.php

For example, a language extension file for the Calls module could contain the following:

/custom/Extension/modules/Calls/ext/Languages/en_us.Import_Menu.php

<?php
// adding Import field changes
$mod_strings['LNK_IMPORT_CALLS'] = 'Import Calls';
$mod_strings['LBL_MODIFIED_NAME'] = 'Modified By';
$mod_strings['LBL_PARENT_TYPE'] = 'Parent Type';
$mod_strings['LBL_PARENT_ID'] = 'Parent ID';
?>
This would add four new display strings to the Calls module.

Shortcuts
It is possible to override or create new Shortcuts menu items.

Master Directories
Files in these directories can be edited and new files can be added to these directories.

• /custom/Extension/application/Ext/Menus/

• /custom/Extension/modules/<MODULE_NAME>/Ext/Menus/

Production Directories
Files in these directories are auto-generated by the system.

81     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

• /custom/application/Ext/Menus/menu.ext.php

• /custom/modules/<MODULE_NAME>/Ext/Menus/menu.ext.php

Description
Shortcut menu files either replace entirely or add to the menu items available in the menus on the
left-hand side of the user interface. In the Master Directories you can have many files like:

• /custom/Extension/modules/Calls/Ext/Menus/New_menu_items.php

• /custom/Extension/modules/Calls/Ext/Menus/Custom_Menus.php

• /custom/Extension/modules/Calls/Ext/Menus/Menu_items.php

During the repair function (Admin->Repair->Quick Repair and Rebuild), all of these files will be
merged together into the production directory and they become the file:

/custom/modules/Leads/ext/Menus/menu.ext.php

For example, a menu extension file for the Calls module could contain the following:

<?php
if(ACLController::checkAccess('Calls', 'import', true)) {

$module_menu[]=Array("index.php?module=Calls&action=MakeIndex",$mod_strings['LNK_INDEX
_CALLS'], "Import");
}
?>

This would add a menu item to the Calls modules Shortcuts menu. The $module_menu array
takes three elements.

• The first is the URL that the menu item will run.

• The second is the text that will be shown on the menu, in this case we added some custom
language text in a separate custom language file that we will go over later in this
document.

• The last is the name of the icon associated with this menu option. This word will have
“.gif” added to the end of it. If you want to use a PNG file here you would rename
import.png to import.gif and load it into the themes/default/images directory. Even
though it is named with the 'gif' extension it will still work.

If you added a $module_menu=array(); to the top of this file, you would effectively clear out
any of the standard menu items. Then you could then replace them all with new definitions.

If the custom file is in the /custom/Extension/application/Ext/Menus/ directory then your menu


changes will affect all shortcut menus in every module.

82    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Layoutdefs
Master Directories
Files in these directories can be edited and new files can be added to these directories.

• /custom/Extension/application/Ext/Layoutdefs/

• /custom/Extension/modules/<MODULE_NAME>/Ext/Layoutdefs/

Production Directories
Files in these directories are auto-generated by the system.

• /custom/application/Ext/Layoutdefs/layoutdefs.ext.php

• /custom/modules/<MODULE_NAME>/Ext/Layoutdefs/layoutdefs.ext.php

Description
Layoutdefs are a little more complex than the other customization types. Each customization is
made across two files, the layout definition file and the actual layout file. In the Master
Directories you can have many files like:

• /custom/Extension/modules/Accounts/Ext/Layoutdefs/_overrideAccountContactsForAccou
nts.php

• /custom/Extension/modules/Accounts/Ext/Layoutdefs/_overrideAccountOpportunitiesForA
ccounts.php

During the repair function (Admin->Repair->Quick Repair and Rebuild), all of these files will be
merged together into the production directory and they become the file:

/custom/modules/Accounts/Ext/Layoutdefs/layoutdefs.ext.php

For example, a layoutdefs extension file for the Accounts module could contain the following:

/custom/Extension/modules/Accounts/ext/Layoutdefs/_overrideAccountContactsForAccounts.php

<?php
$layout_defs["Accounts"]["subpanel_setup"]["accounts_documents"] = array (
'order' => 100,
'module' => 'Documents',
'subpanel_name' => 'default',
'sort_order' => 'asc',
'sort_by' => 'id',
'title_key' => 'LBL_ACCOUNTS_DOCUMENTS_FROM_DOCUMENTS_TITLE',
'get_subpanel_data' => 'accounts_documents',
);

$layout_defs['Accounts']['subpanel_setup']['contacts']['override_subpanel_name'] =
'AccountForAccounts';
?>

83     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

The first array is setting up a subpanel for a new relationship between Documents and Accounts.
While there are many other files required to completely define this module relationship (which
we will go over in the Relationship section below), this file just creates the links to the new
subpanel that would be located at:

custom/modules/Documents/Ext/subpanels/default.php

The second array simply points the system at a new subpanel definition file that will replace the
subpanel that shows Contacts related to Accounts. Since you cannot merge subpanel definition
files, they don't exist in the custom/Extension/ directory. The array in this file would tell the
system to load the file:

custom/modules/Contacts/metadata/subpanels/AccountForAccounts.php

Module Builder
The Module Builder functionality allows programmers to create custom modules without writing code
and to create relationships between new and existing CRM modules. To illustrate how to use Module
Builder, this article will show how to create and deploy a custom module. In this example, a custom
module to track media inquiries will be created to track public relations requests within a CRM system.
This use case is an often requested enhancement for CRM systems that applies across industries.

Creating New Modules


Module Builder functionality is managed within the ‘Developer Tools’ section of Sugar’s
administration console.

Figure 2: Module Builder is part of the ‘Developer Tools’ section of Sugar Administration

Upon selecting ‘Module Builder’, the user has the option of creating a “New Package”. Packages are
a collection of custom modules, objects and fields, that can be published within the application
instance or shared across instances of Sugar. Once the user selects a “New Package”, the user names
and describes the type of Custom Module to be created. A package key, usually based on the
organization or name of the package creator is required to prevent conflicts between two packages
with the same name from different authors. In this case, the package will be named “MediaTracking”
to explain its purpose and a key based on the author name will be used.

84    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Figure 3: The user begins by creating and naming the new Custom Module Package

Once the new package is created and saved, the user is presented with a screen to create a Custom
Module. Upon selecting the “New Module” icon, a screen appears showing six different object
templates.

Understanding Object Templates


Five of the six object templates contain pre-built CRM functionality for key CRM use cases. These
objects are “Company”, “Issue”, “Person”, “File”, and “Sale”. As their title denotes, each of these
templates contain fields and application logic to describe entities similar to “Accounts”, “Cases”,
“Contacts”, “Documents”, and “Opportunities”, respectively. Thus, a person wanting to create a
Custom Module to track a type of account would select the “Company” template. For someone who
would like to track human interactions would select “People”.

For the media tracking use case, the user will use the object template “Issue” because inbound media
requests have similarities to an incoming support case. In both examples, there is an inquiry, a
recipient of the issue, assignment of the issue and resolution. The final object template is named
“Basic” which is the default base object type. This allows the administrator to create their own
custom fields to define the object.

85     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Figure 4: Object templates allow users to create custom modules based on common use cases, such as
company, issue and person.

Upon naming and selecting the Custom Module template named “Issue”, the user can further
customize the module by changing the fields and layout of the application and creating relationships
between this new module and existing standard or custom modules. This edit functionality allows
user to construct a module that meets the specific data requirements of the Custom Module.

Editing Module Fields


Fields can be edited and created using the new field editor. Fields inherited from the custom module's
templates can be relabeled while new fields are fully editable. New fields are added using the “Add
Field” button. This will bring up a tab where you can select the type of field to add as well as any
properties that field type requires. Please see section 18.2fields for information on field types.

86    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Figure 5: Object templates allow users to create custom modules based on common use cases, such as
company, issue and person.

Editing Module Layouts


The layout editor can be used to change the appearance of the screens within the new module,
including the EditView, DetailView and ListView screens. When editing an EditView or DetailView,
new panels and rows can be dragged from the toolbox on the left side to the layout area on the right.
Fields can then be dragged between the layout area and the toolbox. Fields are removed from the
layout by dragging them from the layout area to the recycling icon. Fields can be expanded or
collapsed to take up one or two columns on the layout using the plus and minus icons. List, Search,
Dashlet, and Subpanel views can be edited by dragging fields between hidden/visible/available
columns.

87     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Figure 6: Custom Modules layouts can be edited using a drag-and-drop user interface.

Building Relationships
Once the fields and layout of the Custom Module have been defined, the user then defines
relationships between this new module and existing CRM data by clicking on “View Relationships”.
The “Add Relationship” button allows the user to associate the new module to an existing or new
custom module in the same package. In the case of the Media Tracker, the user can associate the
Custom Module with the existing, standard ‘Contacts’ module that is available in every Sugar
installation using a many-to-many relationship. By creating this relationship, end-users will see the
Contacts associated with each Media Inquiry. We will also add a relationship to the activities module
so that a Media Inquiry can be related to calls, meetings, tasks, and emails.

88    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Figure 7: Module Builder allows users to create relationships between Custom Modules and existing CRM
modules

Publishing and Uploading Packages


Once the user has created the appropriate fields, layout and relationships for the Custom Modules,
this new CRM functionality can be deployed. Clicking the “Deploy” button will deploy the package
to the current instance. This is the reccomended way to test your package while developing. If you
wish to make further changes to your package or custom modules, you should make those changes in
ModuleBuilder, and simply hit the deploy button again. Selecting the “Publish” generates a zip file
with the Custom Module definitions. This is the mechanism for moving the package to a test
environment and then ultimately to the production environment. The “Export” button will produce a
module loadable zip, similar to the “Publish” functionality, except that when the zip is installed, it
will load the custom package into Module Builder for further editing. This is a good method for
storing the custom package in case you would like to make changes to it in the future on another
instance of SugarCRM.

89     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Figure 8: Publishing Packages creates a zip file for the new Custom Module.

Once the new package has been published the administrator must commit the package to the Sugar
system by visiting ‘Module Loader’ within the Sugar Administration console. The user uploads the
files and commits the new functionality to the live application instance.

90    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Figure 9: Module Loader allows users to install third-party extensions and packages to the live Sugar
instance.

Adding Custom Logic using Code


While the key benefit of the Module Builder is that the user is able to create entirely new modules
without the need to write code, there are still some tasks that require writing PHP code. For instance,
adding custom logic or making a call to an external system via a Web Service. This can be done in
one of two methods.

Logic Hooks
One way is by writing PHP code that leverages the event handlers or “logic hooks” available in
Sugar. In order to accomplish this, the developer must create the custom code and then add it to
the manifest file for the “Media Inquiry” package.

Here is some sample code for a simple example of using the logic hooks. This example adds a
time stamp to the description field of the Media Inquiry every time the record is saved.

First, create the file AddTimeStamp.php with the following contents.

<?php
//prevents directly accessing this file from a web browser
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');

91     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

class AddTimeStamp {

function StampIt(& $focus, $event){


global $current_user;
$focus->description .= “\nSaved on ”. date(“Y-m-d g:i a”). “ by ”. $current_user-
>user_name;
}
}
?>

Next register this custom function by creating the file logic_hooks.php with the following
contents.

<?php
// Do not store anything in this file that is not part of the array or the hook
version. This file will
// be automatically rebuilt in the future.
$hook_version = 1;
$hook_array = Array();
// position, file, function
$hook_array['before_save'] = Array();
$hook_array['before_save'][] = Array(1, 'custom',
'custom/modules/Media/AddTimeStamp.php ','AddTimeStamp', 'StampIt');
?>

Now add these two files to the Media Inquiries zip file you just saved. Create a directory called
“SugarModules/custom/” in the zip file and add the two files there. Then modify the
manifest.php in the zip file to include the following definition in the $install_defs[‘copy’]
array.

array (
'from' => '<basepath>/SugarModules/custom',
'to' => 'custom/modules/jsche_Media',
),

Custom Bean files


Another method is to add code directly to the custom bean. This is the somewhat more
complicated approach as it requires understanding the SugarBean class, but is the far more
flexible and powerful approach.

First you must “build” your module. This can be done by either deploying your module or
pressing the publish button. Module Builder will then generate a folder for your package in
“custom/modulebuilder/builds/”. Inside that folder is where Module Builder will have placed the
bean files for your new module(s). In this case we want
“custom/modulebuilder/builds/MediaTracking/SugarModules/modules/jsche_mediareque
st”

Inside you will find two files of interest. The first one is {module_name}_sugar.php. This file is
generated by Module Builder and may be erased by further changes in module builder or
upgrades to the sugar application. You should not make any changes to this file. The second is
{module_name}.php. This is the file where you should make any changes you would like to the

92    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

logic of your module. To add our timestamp, we would add the following code to
jsche_mediarequest.php

function save($check_notify = FALSE) {

global $current_user;

$this->description .= "\nSaved on " . date("Y-m-d g:i a"). " by "


. $current_user->user_name;

parent::save($check_notify);

}
The call to the parent::save function is critical as this will call on the out of box SugarBean to
handle the regular save functionality. To finish, simply re-deploy or re-publish your package from
ModuleBuilder.

You can now upload this module extended with custom code logic into your Sugar application
using the Module Loader as described earlier.

Using the New Module


Once the new module has been uploaded via the module loader, the new Custom Module appears
within the live CRM instance. In this case, the user has created a new module named “Media” which
uses the object template “Issue” to track incoming media inquiries. This new module is associated
with the standard “Contacts” modules to show which journalist has expressed interest. In the example
below, a journalist has requested a product briefing. On one page, users can see the nature of the
inquiry, the journalist who requested the briefing, who the inquiry was assigned to, status and
description.

93     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Figure 10: The new Custom Module “Media” shows incoming media inquiries and associates them with
contacts so the company can better track incoming media requests.

Module Loader
The Module Loader not only installs custom modules but installs the latest patches, themes, language
packs, and Sugar Dashlets. The $upgrade_manifest variable is used to upgrade the application.

The Module Loader relies on a file named manifest.php, which resides in the root directory of any
installable package.

Manifest Overview
The following section outlines the parameters specified in the $manifest array contained in the
manifest file (manifest.php). An example manifest file is included later for your reference.

$manifest array elements provide the Module Loader with descriptive information about the
extension.

o acceptable_sugar_flavors - Contains which Sugar Editions the package can be installed on.
Accepted values are any combination of: OS (valid prior to Sugar 5.0.0), CE (valid after
Sugar 5.0.0), PRO, and ENT.

o acceptable_sugar_versions - This directive contains two arrays:

o exact_matches: each element in this array should be one exact version string, i.e.
“5.0.0e” or “5.1.0”

o regex_matches: each element in this array should be one regular expression designed
to match a group of versions, i.e. “5\\.0\\.0[a-z]”

94    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

o author - Contains the author of the package, i.e. “SugarCRM Inc.”

o copy_files - An array detailing the source and destination of files that should be copied
during installation of the package. See the example manifest file below for details.

o dependencies - A set of dependencies that must be satisfied to install the module. This
contains two arrays:

o id_name : the unique name found in $installdefs.

o version: the version number.

o description - A description of the package. Displayed during installation.

Note: Apostrophes (') are not supported in your description and will cause a Module Loader
error.

o icon - A path (within the package ZIP file) to an icon image that will be displayed during
installation. Examples include: “./patch_directory/icon.gif” and
“./patch_directory/images/theme.gif”

o is_uninstallable - Setting this directive to TRUE allows the Sugar administrator to uninstall
the package. Setting this directive to FALSE disables the uninstall feature.

o name - The name of the package. Displayed during installation. Note: Apostrophes (') are
not supported in your description and will cause a Module Loader error.

o published_date - The date the package was published. Displayed during installation.

o type - The package type. Accepted values are:

o langpack - Packages of type langpack will be automatically added to the “Language”


dropdown on the Sugar Login screen. They are installed using the Upgrade Wizard.

o module - Packages of type module are installed using the Module Loader.

o patch - Packages of type patch are installed using the Upgrade Wizard.

o theme - Packages of type theme will be automatically added to the “Theme”


dropdown on the Sugar Login screen. They are installed using the Upgrade Wizard.

o version - The version of the patch, i.e. “1.0” or “0.96-pre1” .

Installdef Definition
The following section outlines the parameters specified in the $installdef array contained in the
manifest file (manifest.php). An example manifest file is included later for your reference.

$installdef array elements are used by the Module Loader to determine the actual installation steps
that need to be taken to install the extension.

95     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

• id - A unique name for your module, i.e. “Songs”

• copy - An array detailing files to be copied to the Sugar directory. A source path and
destination path must be specified for each file or directory. See the example manifest file
below for details.

• language - An array detailing individual language files for your module. The source path,
destination file, and language pack name must be specified for each language file. See the
example manifest file below for details.

• layoutdefs - An array detailing individual layoutdef files, which are used primarily for setting
up subpanels in other modules. The source path and destination module must be specified for
each layoutdef file. See the example manifest file below for details.

• vardefs - An array detailing individual vardef files, which are used primarily for defining
fields and non many-to-many relationships in other modules. The source path and destination
module must be specified for each vardef file. See the example manifest file below for
details.

• menu - An array detailing the menu file for your new module. A source path and destination
module must be specified for each menu file. See the example manifest file below for details.

• beans - An array specifying the bean files for your new module. The following subdirectives
must be specified for each bean:

o module: Your module’s name, e.g. “Songs”

o class: Your module’s primary class name, e.g. “Song”

o path: The path to your bean file where the above class is defined.

o tab: Controls whether or not your new module appears as a tab.

o relationships - An array detailing relationship files, used to link your new modules
to existing modules. A module name, meta_data path, and module_vardefs path must
be specified for each relationship. See the example manifest file below for details.

o custom_fields - An array detailing custom fields to be installed for your new


module. The following subdirectives must be specified for each custom field:

ƒ name: The internal name of your custom field. Note that your custom field
will be referred to as <name>_c, as “_c” indicates a custom field.

ƒ label: The visible label of your custom field

ƒ type: The type of custom field. Accepted values include text, textarea,
double, float, int, date, bool, enum, and relate.

ƒ max_size: The custom field’s maximum character storage size

96    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

ƒ require_option: Used to mark custom fields are either required or option.


Accepted values include optional and required.

ƒ default_value: Used to specify a default value for your custom field

ƒ ext1: Used to specify a dropdown name (only applicable to enum type


custom fields)

ƒ ext2: Unused

ƒ ext3: Unused

ƒ audited: Used to denote whether or not the custom field should be audited.
Accepted values include 0 and 1.

ƒ module: Used to specify the module where the custom field will be added.

Upgrade Definition
This array definition describes the release(s) leading to the "version" element defined in $manifest.
In the sample manifest below it defines the Songs module versions 1.0 and 1.5 as preceding the
current version 2.0.

Sample Manifest
The following sample manifest file defines the $manifest and $installdef array elements for a new
module (Songs) which depends on two other modules: "Whale Pod" and "Maps". In addition to
defining the $manifest and $installdef array elements it also defines the $upgrade_manifest
array.

<?php
$manifest = array(
'acceptable_sugar_versions' => array(),
'is_uninstallable' => true,
'name' => 'Song Module',
'description' => 'A Module for all your song needs',
'author' => 'Ajay',
'published_date' => '2005/08/11',
'version' => '2.0',
'type' => 'module',
'icon' => '',
'dependencies' => array (
array ('id_name' => 'whale_pod', 'version => '1.0'),
array ('id_name' => 'maps', 'version => '1.5'),
),
);
$installdefs = array (
'id' => 'songs',
'image_dir' => '<basepath>/images',
'copy' => array (
array (
'from' => '<basepath>/module/Songs',
'to' => 'modules/Songs',
),
),
'language' => array (

97     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

'from'=> '<basepath>/administration/en_us.songsadmin.php'
'to_module'=> 'application',
'language'=>'en_us'
),
array (
'from'=>
'<basepath>/administration/en_us.songsadmin.php',
'to_module'=> 'Administration',
'language'=>'en_us'
),
),
'layoutdefs'=> array(
array(
'from'=> '<basepath>/layoutdefs/contacts_layout_defs.php',
'to_module'=> 'Contacts',
),
),
'vardefs'=> array(
array(
'from'=> '<basepath>/vardefs/contacts_vardefs.php',
'to_module'=> 'Contacts',
),
),
'administration'=> array (
array ( 'from'=>'<basepath>/administration/songsadminoption.php',
),
),
),
'beans'=> array (
array (
'module'=> 'Songs',
'class'=> 'Song',
'path'=> 'modules/Songs/Song.php',
'tab'=> true,
)
),
'relationships'=>array (
array (
'module'=> 'Contacts',

'meta_data'=>'<basepath>/relationships/contacts_songsMetaData.php',
'module_vardefs'=>'<basepath>/vardefs/contacts_vardefs.php',

'module_layoutdefs'=>'<basepath>/layoutdefs/contactslayout_defs.php'
),
array (
'module'=> 'Products',

'meta_data'=>'<basepath>/relationships/products_songsMetaData.php',
'module_vardefs'=>'<basepath>/vardefs/products_vardefs.php',

'module_layoutdefs'=>'<basepath>/layoutdefs/productslayout_defs.php'
)
),
'custom_fields'=>array (
'array (
'name'=> 'music_name',
'label'=>'Music Name',
'type'=>'varchar',
'max_size'=>255,

'require_option'=>'optional',
'default_value'=>' ',

98    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

'ext1' => 'name',


'ext2' => 'Accounts',
'ext3' => ' ',
'audited'=>0,
'module'=>'Songs',
)
),
);
array (
'name'=>'label_company',
'label'=>'Label',
'type'=>'relate',
'max_size'=>36,
'require_option'=>'optional',
'default_value'=>'',
'ext1'=>'name',
'ext2'=>'Accounts',
'ext3'=>'', 'audited'=>0,
'module'=>'Songs',
)
),
);

$upgrade_manifest = array (
'upgrade_paths' => array (
'1.0' => array(
'id'=>'songs',
'copy'=>array(
array (
'from'=> '<basepath>/module/Songs',
'to'=> 'modules/Songs',
),
),
),
'1.5' => array (
'id'=>'songs',
'copy' => array(
array (
'from'=> '<basepath>/module/Songs',
'to'=> 'modules/Songs',
),
),
),
),
);
?>

Business Logic Hooks


Custom Logic (or "Business Logic Hooks") allows you to add functionality to certain actions, such as
before a bean save, in an upgrade-safe manner. This is accomplished by defining hooks, which are placed
in the custom/ directory, which will be called in the SugarBean in response to events at runtime. Because
the code is located separate from the core SugarCRM code, it is upgrade-safe.

See this SugarForge project for a complete example of a useful business hook.

99     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Hook Definition
The code that declares your custom logic is located in:
custom/modules/<CURRENT_MODULE>/logic_hooks.php. The format of the declaration follows.

$hook_version
All logic hooks should define the $hook_version that should be used. Currently, the only
supported $hook_version is 1.

$hook_version = 1

$hook_array
Your logic hook will also define the $hook_array. $hook_array is a two dimensional array:

o name: the name of the event that you are hooking your custom logic to

o array: an array containing the parameters needed to fire the hook

A best practice is for each entry in the top level array to be defined on a single line to make it
easier to automatically replace this file. Also, logic_hooks.php should contain only hook
definitions; the actual logic is defined elsewhere.

For example:

$hook_array['before_save'][] = Array(1, test, 'custom/modules/Leads/test12.php',


'TestClass', 'lead_before_save_1');

Available Hooks
The hooks are processed in the order in which they are added to the array. The first dimension is
simply the current action, for example before_save. The following hooks are available:

Application hooks
These hooks do not make use of the $bean argument.

o after_ui_frame

o Fired after the frame has been invoked and before the footer has been invoked

o Available in version 4.5.0 and later

o after_ui_footer

o Fired after the footer has been invoked

o Available in version 4.5.0 and later

o server_round_trip

o Fired at the end of every SugarCRM page

100    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

o Available in version 4.5.0 and later

Module hooks
o before_delete

o Fired before a record is deleted

o Available in version 4.5.0 and later

o after_delete

o Fired after a record is deleted

o Available in version 4.5.0 and later

o before_restore

o Fired before a record is undeleted

o Available in version 4.5.0 and later

o after_restore

o Fired after a record is undeleted

o Available in version 4.5.0 and later

o after_retrieve

o Fired after a record has been retrieved from the database. This hook does not fire
when you create a new record.

o Available in version 4.5.0 and later

o before_save

o Fired before a record is saved.


Note: With certain modules, like Cases and Bugs, the human-readable ID of the
record (like the case_number field in the Case module), is not available within a
before_save call. This is because this business logic simply hasn't been
executed yet.

o Available in version 4.5.0 and later

o after_save

o Fired after a record is saved.


Note: With certain modules, like Cases and Bugs, the human-readable ID of the
record (like the case_number field in the Case module), is not available within a

101     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

before_save call. This is because this business logic simply hasn't been
executed yet.

o Available in version 4.5.0 and later

o process_record

o Fired immediately prior to the database query resulting in a record being made
current. This gives developers an opportunity to examine and tailor the
underlying queries. This is also a perfect place to set values in a record’s fields
prior to display in the DetailView or ListView. This event is not fired in the
EditView.

o Available in version 4.5.0 and later

Hooks for Users module


o before_logout

o Fired before a user logs out of the system

o Available in version 4.5.0 and later

o after_logout

o Fired after a user logs out of the system

o Available in version 4.5.0 and later

o after_login

o Fired after a user logs into the system.

o Available in version 4.5.0 and later

o after_logout

o Fired after a user logs out of the system.

o Available in version 4.5.0 and later

o before_logout

o Fired before a user logs out of the system.

o Available in version 4.5.0 and later

o login_failed

o Fired on a failed login attempt

o Available in version 4.5.0 and later

102    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Options array
The second dimension is an array consisting of:

o Processing index => For sorting before exporting the array

o Label/type => Some string value to identify the hook

o PHP file to include => Where your class is located. Insert into ./custom.

o PHP class the method is in => The name of your class

o PHP method to call => The name of your method

Thus a given class may have multiple methods to fire, each within a single upgrade-safe PHP file.

The method signature for version 1 hooks is:

function NAME(&$bean, $event, $arguments)

Where:

o $bean - $this bean passed in by reference.

o $event - The string for the current event (i.e. before_save)

o $arguments - An array of arguments that are specific to the event.

Packaging Custom Logic Hooks


There are no directives in the manifest.php file to safely install business logic hooks. You have to do
it via the pre_install or post_install scripts. To do this, create a top-level directory in your installer
called 'scripts' and in that directory place a file called pre_install.php.

A pre_install file could look like this:

<?php

if(!defined('sugarEntry'))define('sugarEntry', true);

function pre_install() {

require_once('include/utils.php');

check_logic_hook_file("Accounts", "after_retrieve", array(1, "update_description",


"include/FCKEditor/updateDescription.php", "updateDescription",
"updateDescription"));
}

?>

The check_logic_hook_file() command is looking for three things. First is the module that you
want this hook to affect, in this case "Accounts". The second is the hook itself, in this case
"after_retrieve". The third part is an array which mirrors the $hook_array like this:

103     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

o Processing index => 1

o Label/Type => update_description

o PHP file to include => include/FCKEditor/updateDescription.php

o PHP class the method is in => updateDescription

o PHP method to call => updateDescription

Of course you can call the check_logic_hook_file() command as many times as you want. The
logic behind the command check to make sure that your hook isn't already set and if it is then it
replaces it, making it pretty upgrade-safe. If you have any questions about installing logic hooks look
for me in the forums.

Using Custom Logic Hooks


Above we showed how to create a custom_logic_hook that runs the function updateDescription()
from the class updateDescription (those don't have to be the same, they just are in this example) in
the PHP file updateDescription.php. Below is the actual script from that PHP file.

class updateDescription {
function updateDescription(&$bean, $event, $arguments) {
$bean->description = html_entity_decode($bean->description);
$bean->fetched_row['description'] = $bean->description;
}
}
You see that the $bean is fed into the function and allows access to all of the fields for the currently
selected record. Any changes you make to the array will be reflected in the actual data. For example
in this script we are changing the description field. As you see above there is

$event is set to whatever event is currently running like after_retrieve or before_delete.

Tips & Pitfalls


A few cautions around using logic hooks apply:

o It is not possible to hook logic to beans being displayed in a SubPanel.

o There is no bean that fires specifically for the ListView, DetailView or EditViews user
interface events. Use either the 'process_record' or 'after_retrieve' logic hooks.

o In order to compare new values with previous values to see whether a change has happened,
use $bean->fetched_row['<field>'] (old value) and $bean-><field> (new value) in the
before_save logic hook.

o Make sure that the permissions on your logic_hooks.php file and the class file that it
references are readable by the Web server. If this isn’t done, the files will not be read by the
SugarCRM application and your business logic extensions will not work.
For example, for *nix developers who are extending the Tasks logic, that means you should

104    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

do the following command for the logic_hooks file and the same command for the class file
that will be called.

[sugarcrm]# chmod +r custom/modules/Tasks/logic_hooks.php

o Make sure that the entire custom/ directory is writable by the Web server, otherwise the
logic hooks code will not work properly.

105     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

User Interface Customizations


While the hope of the metadata framework is to abstract some of the value retrieval and display logic for
the modules, there will inevitably be a need to customize the framework with separate hooks and logic
pertaining to the module's unique business needs.

Custom Grouping of Values


This is a common scenario in DetailViews, especially for address blocks. This can be achieved as
follows:

array (
'name' => 'date_modified',
'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY}
{$fields.modified_by_name.value}',
'label' => 'LBL_DATE_MODIFIED',
),

This will group the date_modified value and the modified_by_name values together with the
$APP.LBL_BY label in between. The 'customCode' key is a direct Smarty inline code replacement.
At the time of parsing the $fields array will be populated with the values populated for the request
bean instance.

Custom Buttons
By default, the metadata framework provides default implementations for CANCEL, DELETE,
DUPLICATE, EDIT, FIND DUPLICATES and SAVE buttons. However, you may wish to use some
of the default buttons, but add additional buttons. Here's an example:

'templateMeta' => array('form' =>


array('buttons'=>array('EDIT', 'DUPLICATE', 'DELETE',
array('customCode'=>
'<form action="index.php" method="POST" name="Quote2Opp"
id="form">
<input title="{$APP.LBL_QUOTE_TO_OPPORTUNITY_TITLE}"
accessKey="{$APP.LBL_QUOTE_TO_OPPORTUNITY_KEY}"
class="button"type="submit"
name="opp_to_quote_button"
value="{$APP.LBL_QUOTE_TO_OPPORTUNITY_LABEL}">
</form>'
),

Here we are adding a custom button with the label defined in the Smarty variable
{$APP.LBL_QUOTE_TO_OPPORTUNITY_LABEL}. The EDIT, DUPLICATE and DELETE buttons are
rendered and then the snippet of code in this 'customCode' block is added.

The code to render the buttons specified in the metadata files may be found in
include/Smarty/function.sugar_button.php.

106    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Creating New Custom Displays


In this scenario, you wish to take advantage of the metadata framework to do some of the processing
for a subset of the fields. However, the provided user interface generated does not meet the needs of
your module which requires richer UI functionality. Typically this scenario occurs when the
EditView or DetailView for the module contains UI components that do not fit the framework of a
table layout that produced by the metadata. For example, in addition to displaying the properties for
the bean instance of the module, there is also a lot of information to be displayed for related beans,
mashups, etc.

This type of customization may be achieved by a combination of overriding the footer.tpl file in the
templateMeta section of the metadata file and creating a view.edit.php file to override the default
MVC EditView handling. For example, consider the Quotes module's editviewdefs.php file:

'templateMeta' => array('maxColumns' => '2',


'widths' => array(
array('label' => '10', 'field' => '30'),
array('label' => '10', 'field' => '30')
),
'form' =>
array('footerTpl'=>'modules/Quotes/tpls/EditViewFooter.tpl'),
),

Note: You don't have to necessarily create a view.edit.php file, but usually at this point of
customization, you will want to add variables to your customized template that is not assigned by the
generic EditView handling from the MVC framework. See the next example (Overriding the View)
for more information about sub-classing the EditView and assigning Smarty variables to the resulting
templates.

Your EditViewFooter.tpl file can now render the necessary user interface code that the generic
metadata framework could not:

{$SOME_CRAZY_UI_WIDGET} <----- You can either create this HTML in edit.view.php or


place it here
<applet codebase="something"> <---- Let's add an Applet!
</applet>
{{include file='include/EditView/footer.tpl'}} <--- Include the generic footer.tpl
file at the end

Had you wished to edit the top panel to provide customized widgets then you could override the
header.tpl file instead and control the behavior there. In that scenario, the smarty tag to include the
generic header.tpl would likely appear at the top of the custom template file.

Overriding the View


Using the MVC framework, you define your module's own view.edit.php or view.detail.php file to
subclass ViewEdit (for EditView) or ViewDetail (for DetailView). Then you override either the
process or display methods to do any intermediary processing as necessary. This technique should be
employed when you still want to take advantage of the rendering/layout formatting done by the
metadata framework, but wish to tweak how some of the values are retrieved.

107     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

// Contents of module/[$module]/view/view.edit.php file


require_once('include/json_config.php');
require_once('include/MVC/View/views/view.edit.php');
class CallsViewEdit extends ViewEdit {
function CallsViewEdit(){
parent::ViewEdit();
}

function display() {
global $json;
$json = getJSONobj();
$json_config = new json_config();
if (isset($this->bean->json_id) && !empty ($this->bean->json_id)) {
$JavaScript = $json_config->get_static_json_server(false, true, 'Calls', $this-
>bean->json_id);
} else {
$this->bean->json_id = $this->bean->id;
$JavaScript = $json_config->get_static_json_server(false, true, 'Calls', $this-
>bean->id);
}

// Assign the Javascript code to Smarty .tpl


$this->ss->assign('JSON_CONFIG_JAVASCRIPT', $JavaScript);
parent::display();
}
}

In the file modules/Calls/metadata/editviewdefs.php we have the following defined for the


templateMeta->JavaScript value:

'JavaScript' => '<script type="text/JavaScript">{$JSON_CONFIG_JAVASCRIPT}</script>'

Here the $JSON_CONFIG_JAVASCRIPT Smarty variable was the result of a complex operation and not
available via the vardefs.php file (i.e. there is no JSON_CONFIG_JAVASCRIPT declaration in the
vardefs.php file).

Creating a Custom SugarField


Let's try to create a new type of field for rendering a YouTube video. In this example, we will use a
custom text field in the Contacts module and then override the DetailView of the custom field in the
metadata file to link to our YouTube video. Here are the steps:

1) Create a custom text field in the Contacts module from the Studio editor

2) Add this custom text field to both the EditView and DetailView layout

3) Save and deploy both of the layout file changes

4) Create a directory include/SugarFields/Fields/YouTube. The name of the directory


(YouTube) corresponds to the name of the field type you are creating.

5) In include/SugarFields/Fields/YouTube directory, create the file DetailView.tpl. For the


DetailView we will use the "embed" tag to display the video. In order to do this we need to
add in the template file:

108    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

{if !empty({{sugarvar key='value' string=true}})}


<object width="425" height="350">
<param name="movie" value="http://www.youtube.com/v/{{sugarvar
key='value'}}></param>
<param name="wmode" value="transparent"></param>
<embed src="http://www.youtube.com/v/{{sugarvar key='value'}}"
type="application/x-shockwave-flash"
wmode="transparent" width="425" height="350">
</embed>
</object>
{/if}

You will notice that we use the "{{" and “}}” double brackets around our variables. This implies that
that section should be evaluated when we are creating the cache file. Remember that Smarty is used
to generate the cached templates so we need the double brackets to distinguish between the stage for
generating the template file and the stage for processing the runtime view.

Also note that will use the default EditView implementation that is provided by the base sugar field.
This will give us a text field where people can input the YouTube video id so you do not need to
create EditView.tpl. Also, we do not need to provide a PHP file to handle the SugarField processing
since the defaults will suffice.

6) Now go to custom/modules/Contacts/metadata/detailview.php and add a type override to


your YouTube field and save. In our example, the custom field was named "youtube".

array (
'name' => 'youtube_c',
'type' => 'YouTube',
'label' => 'LBL_YOUTUBE',
),

Your custom field is now ready to be displayed. You can now find an id value of a YouTube video to
insert into the EditView and render the video content in the DetailView! Remember to set your
system to Developer Mode or delete the EditView.tpl or DetailView.tpl files in the
cache/modules/Contacts directory.

Adding QuickSearch to a Custom Field


1. Include the default configs from QuickSearchDefaults.php. Most of the time you can use the
predefined configurations and scripts.

require_once('include/QuickSearchDefaults.php');
$qsd = new QuickSearchDefaults();
2. Then set up the config for the input box you wish to have SQS. Account, Team, and User configs
are available. The following configures SQS for account search on input box w/ id of
'parent_name', user and team in similar fashion with defaults.

$sqs_objects = array('parent_name' => $qsd->getQSParent(),


'assigned_user_name' => $qsd->getQSUser(),
'team_name' => $qsd->getQSTeam());
Notes on structure of config - replace the default parameters if they are different for the page.

109     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

o method: Unless you make a new method on the JSON server, keep this as query.

o populate_list: This defines the id's of the fields to be populated after a selection is made.
QuickSearch will map the first item of field_list to the first item of populate_list. ie.
field_list[0] = populate_list[0], field_list[1] = populate_list[1].... until the end of populate list.

o limit: reduce from 30 if query is large hit, but never less than 12.

o conditions: options are like_custom, contains, or default of starts with


if using 'like_custom' also define 'begin'/'end' for strings to prepend and postpend to the user
input

o disable: set this to true to disable SQS (optional, useful for disabling SQS on parent types in
calls for example)

o post_onblur_function: this is an optional function to be called after the user has made a
selection. It will be passed in an array with the items in field_list as keys and their
corresponding values for the selection as values.

$sqs_objects = array('account_name' => // this is the id


array(
// the method on to use on the JSON server
'method' => 'query',
'modules' => array('Accounts'), // modules to use
'field_list' => array('name', 'id'), // columns to select
'populate_list' => array('account_name', 'account_id'), // id's of the html tags to
populate with the columns.
'conditions' => // where clause, this code is for any account names that have A WORD
beginning with ...
array(array('name'=>'name','op'=>'like_custom','end'=>'%','value'=>''),
array('name'=>'name','op'=>'like_custom','begin'=>'% ','end'=>'%','value'=>'')),
'group' => 'or', // grouping of the where conditions
'order' => 'name', // ordering
'limit' => '30', // number of records to pull
'no_match_text' => $app_strings['ERR_SQS_NO_MATCH'] // text for no matching results
),
3. Include the necessary javascript files if sugar_grp1.js is not already loaded on the page.

$quicksearch_js = '<script type="text/javascript" src="' .


getJSPath('include/javascript/sugar_grp1.js') . '"></script>';
4. Assign your config array to sqs_objects (important!)

$quicksearch_js .= '<script type="text/javascript" language="javascript">


sqs_objects = ' . $json->encode($sqs_objects) . '</script>';
5. Add validation so that if there is no matching id for what the user has entered in an SQS field, an
alert shows. This is for fields such as assigned users where the form must submit a valid ID.

$javascript->addToValidateBinaryDependency('account_name', 'alpha',
app_strings['ERR_SQS_NO_MATCH_FIELD'] .
$mod_strings['LBL_MEMBER_OF'], 'false', '', 'parent_id');
6. Add id tags and class name to the input box. Note that the input box must have
class="sqsEnabled"!

110    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

<input class="sqsEnabled" id="account_name" name='account_name' size='30' type='text'


value="{ACCOUNT_NAME}">
<input id='account_id' name='account_id' type="hidden" value='{ACCOUNT_ID}'>

Having trouble? Take a look at the file module/Contacts/BusinessCard.php.

Tips & Pitfalls


This section provides some tips you will find useful in using the new MVC and metadata framework
and pitfalls that you may run into from the subtle details of the metadata framework that sometimes
cause frustration and confusion. We attempt to list some common scenarios encountered and how to
address them.

Grouping Required Fields Together


To group all required fields together all you need to do is set the config to:

$GLOBALS['sugar_config']['forms']['requireFirst'] = true;

Displaying data on EditViews with a read-only ACL setting


$GLOBALS['sugar_config']['showDetailData'] = true;

The field value specified in metadata does not appear


This usually happens when the user is attempting to specify a variable name in the module's class
definition, but not in the vardefs.php file. For example, consider the Products module. In the
Products.php class file there is the variable:

var $quote_name;
If you attempt to retrieve the value in your metadata file as follows:

...
array (
'quote_name',
'date_purchased',
)
...

You must also make sure that 'quote_name' is specified in the vardefs.php file:

'quote_name' =>
array (
'name' => 'quote_name',
'type' => 'varchar',
'vname' => 'LBL_QUOTE_NAME',
'source'=>'non-db',
'comment' => 'Quote Name'
)

This is because the metadata framework populates the Smarty variable $fields using the variables
listed in the vardefs.php file. If they are not listed, there is no way for the metadata framework to
know for sure which class variables have been set and are to be used. The metadata framework

111     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

works in conjunction with ACL (Access Control Level) checks in the system and these are tied to
fields defined in the vardefs.php file.

The field value specified in metadata does not appear but is in vardefs.php
This may occur if the variable in the module has not been initialized. The metadata framework
invokes the fill_in_additional_detail_fields() method so be sure the values are either set in the
constructor or in the fill_in_additional_detail_fields() method.

A good strategy to debug the Smarty templates that are generated via the metadata files is to
check the cache/modules/<module> directory for the .tpl files (DetailView.tpl, EditView.tpl,
etc.). Enable the Developer Mode setting under the Advanced panel found through the Admin -
>System Settings link to allow for the Smarty templates to be regenerated on every request.

Creating New Sugar Dashlets


The simplest Sugar Dashlet to create is a Module View. These are customizable ListViews of Sugar
Dashlets. For this section we will use the MyAccountsDashlet as an example.

MyAccountsDashlet.php:

// include the base class


require_once('include/Dashlets/DashletGeneric.php');
// required for a seed bean
require_once('modules/Accounts/Account.php');

class MyAccountsDashlet extends DashletGeneric {


// takes an $id, and $def that contains the options/title/etc.
function MyAccountsDashlet($id, $def = null) {
require_once('MyAccountsDashlet.data.php');
parent::DashletGeneric($id, $def);
global $current_user, $app_strings;
$this->searchFields =
$DashletData['MyAccountsDashlet']['searchFields'];
$this->columns =
$DashletData['MyAccountsDashlet']['columns'];
All the metadata for this Sugar Dashlet is defined in the constructor. $searchFields are the search inputs
that can be applied to the view. Defining these here will tell which input fields to generate corresponding
filters when the user configures the Sugar Dashlet.

$columns define the available columns to the user. These contain the visible columns and the columns the
user can make visible. These are defined in MyAccountsDashlet.data.php so that Studio can modify them
easily.

// define a default title


if(empty($def['title'])) $this->title = ‘My Account Dashlet’;

$this->seedBean = new Account();


}
}
A seed bean is also required.

MyAccountsDashlet.data.php:

112    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

$DashletData['MyAccountsDashlet']['searchFields'] =
array('date_entered' => array('default' => ''));
$DashletData['MyAccountsDashlet']['columns'] = array(
'name' => array(
'width' => '40',
'label' => ‘LBL_LIST_ACCOUNT_NAME’,
'link' => true, // is the column clickable
'default' => true // is this column displayed by default
),
'billing_address_state' => array(
'width' => '8',
'label' => 'LBL_BILLING_ADDRESS_STATE’)
);
This file along with the .meta.php file is enough to create a generic Module View Sugar Dashlet.

Custom Sugar Dashlets


Sugar Dashlets are more than generic Module Views. They can provide unlimited functionality and
integration.

For this section we will use the JotPad Sugar Dashlet as an example. The JotPad is a simple note
taking Sugar Dashlet. A user double clicks on the Sugar Dashlet and can enter any text in the Sugar
Dashlet. When the user clicks outside of the textarea, the text is automatically saved via AJAX.

There are 6 files that define this Sugar Dashlet

1. JotPadDashlet.php – JotPad Class

2. JotPadDashlet.meta.php – meta data about the Sugar Dashlet

3. JotPadDashlet.tpl – Display Template

4. JotPadDashletOptions.tpl – Configuration template

5. JotPadDashletScript.tpl - Javascript

6. JotPadDashlet.en_us.lang.php – English Language file

JotPadDashlet.php:

// this extends Dashlet instead of DashletGeneric


class Dashlet extends Dashlet {
var $savedText; // users's saved text
var $height = '100'; // height of the pad

function JotPadDashlet($id, $def) {


$this->loadLanguage('JotPadDashlet'); // load the language strings

// load default text is none is defined


if(!empty($def['savedText']))
$this->savedText = $def['savedText'];
else
$this->savedText = $this->DashletStrings['LBL_DEFAULT_TEXT'];

// set a default height if none is set


if(!empty($def['height']))
$this->height = $def['height'];

113     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

// call parent constructor


parent::Dashlet($id);

// Dashlet is configurable
$this->isConfigurable = true;
// Dashlet has JavaScript attached to it
$this->hasScript = true;

// if no custom title, use default


if(empty($def['title']))
$this->title = $this->DashletStrings['LBL_TITLE'];
else
$this->title = $def['title'];
}

// Displays the Dashlet


function display() {}

// Displays the JavaScript for the Dashlet


function displayScript() {}
// Displays the configuration form for the Dashlet
function displayOptions() {}

// called to filter out $_REQUEST object when the


// user submits the configure dropdown
function saveOptions($req) {}

// Used to save text on textarea blur.


// Accessed via Home/CallMethodDashlet.php
function saveText() {}
}
JotPadDashletOptions.tpl:

<form name='configure_{$id}' action="index.php" method="post" onSubmit='return


SUGAR.Dashlets.postForm("configure_{$id}", SUGAR.sugarHome.uncoverPage);'>

The important thing to note here is the onSubmit. All configure forms should have this statement to
uncover the page to remove the configuration dialog.

NOTE: It is important to separate your JavaScript into a separate JavaScript file. This is because
Sugar Dashlets are dynamically added to a page via AJAX. The HTML included into JavaScript is
not evaluated when dynamically included.

It is important that all JavaScript functions are included in this script file. Inline JavaScript (<a href
onclick=’’ etc) will still function. If the Sugar Dashlet has JavaScript and a user dynamically adds it
to the page, the Sugar Dashlet will not be accessible until after the user reloads the page.

Therefore it is beneficial to use as many generic methods in Dashlet.js as possible


(Dashlets.callMethod() specifically!).

JotPadDashletScripts.tpl:

{literal}<script>
// since the Dashlet can be included multiple times a page,

114    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

// don't redefine these functions


if(typeof JotPad == 'undefined') {
JotPad = function() {
return {
blur: function(ta, id) {}, // called when textarea is blurred
edit: function(divObj, id) {}, // called when textarea is dbl clicked
saved: function(data) {}, // callback for saving
}();
}
</script>{/literal}

Please refer to the file for more detail comments.

Packaging Custom Sugar Dashlets


To make a Sugar Dashlet Module Installable, you will need to package with the following also
included in the manifest.php files.

$installdefs = array( 'id'=> 'jotpad', 'Dashlets'=> array( array('name' => 'JotPad',


'from' => '<basepath>/JotPad', ), ), );

Refreshing the Sugar Dashlet Cache


To add a Sugar Dashlet to your SugarCRM installation, you can use the Module Loader to install
your Sugar Dashlet Package. However, for development purposes, to make the Sugar Dashlet
available to add to the home page you will need to run the Repair Sugar Dashlet Link in the
Admin Repair Panel at least once after you’ve created your Sugar Dashlet.

This will rebuild the cache file /<cache dir>/Dashlets/Dashlets.php by scanning the folders
/modules/ and /custom/modules/ for Dashlet Files.

Creating Custom Chart Dashlets


Creating a custom chart dashlet is very similar to how we created the MyAccountsDashlet above. The
main difference is that you will need to override the display() method in your class to build the
chart, using the SugarChart library included with SugarCRM. Below is an example display()
method as used in the Outcome by Month dashlet.

public function display()


{
$currency_symbol = $GLOBALS['sugar_config']['default_currency_symbol'];
if ($GLOBALS['current_user']->getPreference('currency')){
require_once('modules/Currencies/Currency.php');
$currency = new Currency();
$currency->retrieve($GLOBALS['current_user']->getPreference('currency'));
$currency_symbol = $currency->symbol;
}

require("modules/Charts/chartdefs.php");
$chartDef = $chartDefs['outcome_by_month'];

require_once('include/SugarCharts/SugarChart.php');
$sugarChart = new SugarChart();
$sugarChart->setProperties('',
translate('LBL_OPP_SIZE', 'Charts') . ' ' . $currency_symbol . '1'
.translate('LBL_OPP_THOUSANDS', 'Charts'),
$chartDef['chartType']);
$sugarChart->base_url = $chartDef['base_url'];

115     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

$sugarChart->group_by = $chartDef['groupBy'];
$sugarChart->url_params = array();
$sugarChart->getData($this->constructQuery());

$xmlFile = $sugarChart->getXMLFileName($this->id);
$sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML());

return $this->getTitle('<div align="center"></div>') .


'<div align="center">' . $sugarChart->display($this->id, $xmlFile, '100%',
'480', false) . '</div><br />';
}

protected function constructQuery()


{
$query = "SELECT sales_stage,".
db_convert('opportunities.date_closed','date_format',array("'%Y-
%m'"),array("'YYYY-MM'"))." as m, ".
"sum(amount_usdollar/1000) as total, count(*) as opp_count FROM
opportunities ";
$query .= " WHERE opportunities.date_closed >= ".db_convert("'".$this-
>obm_date_start."'",'datetime') .
" AND opportunities.date_closed <= ".db_convert("'".$this-
>obm_date_end."'",'datetime') .
" AND opportunities.deleted=0";
if (count($this->obm_ids) > 0)
$query .= " AND opportunities.assigned_user_id IN ('" .
implode("','",$this->obm_ids) . "')";
$query .= " GROUP BY sales_stage,".

db_convert('opportunities.date_closed','date_format',array("'%Y-%m'"),array("'YYYY-
MM'")) . " ORDER BY m";

return $query;
}

Creating New Themes


Themes encompass the user interface look and feel. This includes the colors, images and layout of the
major components of the user interface. While Sugar includes several themes with the base installation, it
is possible to create a new theme unique to your business or personal tastes.

Overview
Every time a Sugar screen is rendered to the browser, the system loads a Sugar theme for display
based upon the value set in the variable:

$_SESSION['authenticated_user_theme'];

If no value is set in the authenticated_user_theme variable, then Sugar will use the value set in:

$GLOBALS['sugar_config']['default_theme'];

Understanding exactly where and how $_SESSION['authenticated_user_theme'] is set is less


important at this point than understanding the basic logic behind it:

o if there is an authenticated user and that user has a personal theme preference defined,

116    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

o then set $theme to that value

o else set $theme to the system default value

You will see at the bottom of index.php that the HTML is eventually rendered by calling or
"including" the following three files:

include('themes/'.$theme.'/header.php');
include($currentModuleFile);
include('themes/'.$theme.'/footer.php');

The $theme value defines which header and footer are used from the themes directory. Each screen is
essentially a "header" and "footer" wrapped around the $currentModuleFile "body", which is
determined by the POST parameters sent into index.php.

Each directory underneath the <sugar_root>/themes/ directory defines a different theme. There are
certain files that every SugarCRM theme must contain. Those are:

o themes/<your_theme>/config.php - defines the name of the theme and the minimum Sugar
version the theme will work in.

o themes/<your_theme>/footer.php - defines the HTML rendered at the bottom of the page.

o themes/<your_theme>/header.php - defines the HTML rendered at the top and the left of
each page.

o themes/<your_theme>/layout_utils.php - defines a series of helper functions that draw the


HTML for group boxes round forms and other layout components. By modifying the code in
this file, you can change the look and feel of form headers/footers, form titles, graphs, etc. A
designer could choose to organize the logic included in these files in any matter he sees fit.

o themes/<your_theme>/style.css - defines the style sheet for the theme. All of the different
classes used throughout the app are typically defined in this file. You could break them out
into other files if you so chose, but the convention is to use style.css.

o themes/<your_theme>/header.html - we use a PHP template library called Xtemplates for


separating the business logic from the presentation in the app. Xtemplates essentially allow
you to define a series of dynamic tags in a PHP file (header.php in this case) and then
reference those tags in an HTML file. You are not required to use a header.html with your
header.php, but it is the convention.

Steps to Create a New Theme


To create a new theme, simply cut and paste any one of the existing themes we ship out of the box to
a new directory and start modifying it. Some ideas for possible changes would be:

o Add new images in the page header/footer or in the form headers/footers

o Change the color scheme

117     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

o Move around the layout of the search box.

o Change the icons for each module.

Packaging Custom Themes


The Upgrade Wizard, accessible through the Admin screen, allows you to apply themes without
needing to unzip the files manually. The theme is also actually added to the “Theme” dropdown on
the Sugar Login screen.

The Upgrade Wizard relies on a file named manifest.php, which should reside alongside the root
directory of your theme ZIP file.

The following section outlines the format of the manifest file. An example manifest file can be found
in the following section.

o acceptable_sugar_flavors Contains which Sugar Editions the package can be installed on.
Accepted values are any combination of: CE, PRO, and ENT.

o acceptable_sugar_versions This directive contains two arrays:

o exact_matches: each element in this array should be one exact version string, i.e.
“5.0.0e” or “5.1.0”

o regex_matches: each element in this array should be one regular expression designed
to match a group of versions, i.e. “5\\.0\\.0[a-z]”

o author Contains the author of the package, e.g. “SugarCRM Inc.”

o copy_files An array detailing the source and destination of files that should be copied during
installation of the package. See the example manifest file below for details.

o description A description of the package. Displayed during installation.

o icon A path (within the package ZIP file) to an icon image that will be displayed during
installation. Examples include “./patch_directory/icon.gif” and
“./patch_directory/images/theme.gif”

o is_uninstallable Setting this directive to TRUE allows the Sugar administrator to uninstall
the package. Setting this directive to FALSE disables the uninstall feature.

o name The name of the package. Displayed during installation.

o published_date The date the package was published. Displayed during installation.

o type The package type. This should be set to “theme”

o version The version of the patch, i.e. “1.0” or “0.96-pre1”

118    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Example Theme Manifest File


The following is an example manifest.php file, for the GoldenGate theme:

<?php
$manifest = array (
'acceptable_sugar_versions' =>
array (
'exact_matches' =>
array (
),
'regex_matches' =>
array (
0 => '3.5.[01][a-z]?'
),
),
'acceptable_sugar_flavors' =>
array (
0 => 'OS',
1 => 'PRO',
2 => 'ENT',
),
'name' => 'Golden Gate Theme',
'description' => 'San Francisco inspired theme',
'author' => 'SugarCRM Inc.',
'published_date' => '2005-09-15 16:00:00',
'version' => '3.5.1',
'type' => 'theme',
'is_uninstallable' => TRUE,
'icon' => 'GoldenGate/images/Themes.gif',
'copy_files' =>
array (
'from_dir' => 'GoldenGate',
'to_dir' => 'themes/GoldenGate',
'force_copy' =>
array (
),
),
); ?>
Example File Structure: The following is an example of the file structure of the GoldenGate
theme:

GoldenGate.zip
| manifest.php | \---GoldenGate
| config.php
| cookie.js
| footer.php
| <more files>
|
\---images
accept_inline.gif
AccountReports.gif
Accounts.gif
<more images>

You’ll need to create a root directory that contains the theme directory. The name of this root
directory (i.e. GoldenGate) is what should be used in the from_dir element of the copy_files array
in manifest.php. You’ll also need to place your manifest.php alongside this root directory. Create
a ZIP file containing the root directory and the manifest.php file at the top level. Now your
language pack is ready to be installed with the Upgrade Wizard.

119     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

Tips & Pitfalls


Pick your Canvas
Think about how you want the general look and feel of your theme, and see which out-of-the-box
existing Sugar theme best fits. This will reduce any extra work that may come out of rearranging
the layout because you chose the first theme you saw.

Replace All
When changing colors in the css files, do a “replace all” on the file. For example, if you are
changing the color ‘#FF0000’ to ‘#CC0000’, change all instances of ‘#FF0000’ to ‘#CC0000’.
Eventually you will get to a point where you may want your changes to only affect one class, and
may have to go back and refine some of the mass changes. However doing this initially will
usually result favorably and save you some time.

Check your work


So you have all your css laid out and your home page looks good? Did you check your Edit and
List views? Did you check the calendar popup widgets (from date fields)? Often themes
developers forget to check the css for Sugar Dashlets, reports and charts. Don’t forget to do a
thorough check and keep in mind that you may have to tweak with navigation.css,
layout_utils.php, and sugarColors.xml files before being finally done.

Personalize your theme


Remember this is your theme now. If you want to add a new div, or introduce a new class, you
don’t have to make it fit within the confines of the theme you started with. Most of the images
are transparent and work fine, but changing the look and feel of those would add an extra degree
of customization. So go ahead and add your flash intro, embedded mp3 or Star Wars Background
(C’mon, you know you were thinking about a Star Wars theme).

Adding Multiple Languages


SugarCRM as an application platform is internationalized and localizable. Data is stored and presented in
the UTF8 codepage allowing for all character sets to be used. Sugar provides a language pack framework
allowing developers to build support for any language to be used in the display of user interface labels.

Adding a language is a simple process. Two solutions exist to add your own language to SugarCRM.

When you will add your new language you will have to choose a language prefix. While you can choose
any key value you want, we recommend following the standard locale naming convention. For example,
en_en for English, en_us for US English, ge_ge for German or ge_ch for Swiss German. This key value
will be the prefix for all of your new language files.

Add a Language
You can directly add a new language to SugarCRM without using a Language Pack.

Here are the necessary steps:

120    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

1. Add the new language you are creating to the $languages variable in the config.php file. For
instance, to add Spanish, first modify the config.php file in the root of your Sugar installation to
reference the new language pack.

$sugar_config[`languages`] = array('en_us'=>'US English','es_es'=>'Espanol’);

Note: You can also set the default language in the config.php. This value is used if a user does not
specify a language while logging into the application.

2. Cut and paste each of the en_us.lang.php string files that ship with Sugar Open Source into a new
file (<new>.lang.php) with the new prefix you set in the step above.

There are two general locations where you will need to create the new language files:

o include/language/<new>.lang.php - This file contains the strings common across the entire
application. This file must exist for each language defined in config.php.

o modules/<some_module>/language/<new>.lang.php - These files contain the strings specific


to each module.

Note: Some language files that ship with Sugar are not named “en_us.lang.php” but are “.html” or
“.tpl” files. These files are used for the inline help system. A complete language pack will include the
translated versions of these files as well.

3. After you create your new files by cutting and pasting the en_us.lang.php files, open each file and
translate the strings from English. The strings are defined inside of global arrays and the array
syntax does need to be maintained for everything to work. A common problem you will quickly
see if the array syntax is off is that the user interface doesn't display at all (just a blank page).

Note: In the include/language/<new>.lang.php file, you will see that there are two global arrays
defined. The $app_list_strings array is actually an array of arrays. The key values in this array must
not be changed. There are comments and examples in the code that should keep you on track.

Creating Language Packs


A Language Pack is a compressed file loadable through Module Loader. It is the best solution to add
a language to SugarCRM. Indeed, it is easier to maintain and to port to other instances of SugarCRM.

There are different ways to create a Language Pack:

• You can build a Language Pack using one of the tools available on SugarForge like
“SugarCRM Translation Module” or “Sugar Translation Suite”.

• You can create it using an existing Language Pack:

o Download an existing Language Pack.

o Note: Be careful to choose a language pack up to date and which is working.

121     Sugar Developer Guide 
Chapter 5   Customizing Sugar 

o Uncompress it and be careful to keep the folder architecture.

o Rename all the files with a name starting with the language prefix (for example
“es_es” if you downloaded the Spanish Language Pack) by replacing the old prefix
(“es_es”) with the prefix of your new language. Be careful to not modify the
manifest.php file and the name of the folders.

o Open each file that you have renamed and translate the strings from English. The
strings are defined inside of global arrays and the array syntax does need to be
maintained for everything to work. A common problem you will quickly see if the
array syntax is off is that the user interface doesn't display at all (just a blank page).

o Modify the manifest.php file based on the file changes you made.

o Compress back everything in a zip file.

o You can now load this Language Pack using Module Loader.

• You can create from start to end:

o Follow the steps of “Add a Language” above.

o When you’re finished and it is working on your test instance, you’ll need to package
it to be installed.

o Module Loader allows you to apply language packs without needing to add the
language to the $languages array in config.php. The Module Loader relies on a file
named manifest.php, which should reside alongside the root directory of your
language pack ZIP file.

o Note: An overview of the manifest file is available in the section 4.3.1.

The following is an example manifest.php file, for the Portugese (Brazilian) language pack:

<?php
$manifest = array (
'acceptable_sugar_versions' =>
array (
'exact_matches' =>
array (
),
'regex_matches' =>
array (
0 => '5\.0\.0[a-z]?'
),
),
'acceptable_sugar_flavors' =>
array (
0 => 'CE',
1 => 'PRO',
2 => 'ENT',
),
'name' => 'Portugese (Brazilian) language pack',
'description' => 'Portugese (Brazilian) language pack',

122    Sugar Developer Guide 
Chapter 5   Customizing Sugar 

'author' => 'Your name here!',


'published_date' => '2008-07-29 22:50:00',
'version' => '5.0.0',
'type' => 'langpack',
'icon' => '',
'is_uninstallable' => TRUE,
'copy_files' =>
array (
'from_dir' => 'pt_br_500',
'to_dir' => '',
'force_copy' =>
array (
),
),
);
?>
The following is an example of the file structure of the Portugese (Brazilian) language pack:

SugarEnt-5.0.0-lang-pt_br-2008-07-29.zip
|
|___ manifest.php
|
|___ pt_br_500
|
|___ include
| |___language
| pt_br.lang.php
|
|___ modules
|
|___ Accounts
| |
| |___ language
| pt_br.lang.php
|
|___ Activities
| |___ language
| pt_br.lang.php
|
|___ <other module directories>

You’ll need to create a root directory that contains the ./include/ and ./modules/ directories of the
language pack.

The name of this root directory (i.e. pt_br_500) is what should be used in the from_dir element of the
copy_files array in manifest.php. You’ll also need to place your manifest.php alongside this root
directory.

Then you’ll need to copy all the language files that you created in the steps of “Add a Language” into
these directories. Be careful to keep the same directory structure (for examples if the file was in
modules/Accounts/language copy/paste it in pt_br_500/modules/Accounts/language).

Create a ZIP file containing the root directory and the manifest.php file at the top level. Now your
language pack is ready to be installed with the Module Loader!

123     Sugar Developer Guide 

You might also like